Skip to main content

Full text of "Lisp lore : a guide to programming the Lisp machine"

See other formats


LISP 

LORE: 

A  GUIDE  TO 
PROGRAMMING 
THE  LISP 
MACHINE 


Hank  Bromley  ^g. 


LISP  LORE:  A  GUIDE  TO 
PROGRAMMING  THE  LISP  MACHINE 


AT&T 

LISP  LORE:  A  GUIDE  TO 
PROGRAMMING  THE  LISP  MACHINE 


by 


Hank  Bromley 

AT&T  Bell  Laboratories 


W 


KLUWER  ACADEMIC  PUBLISHERS 

Boston/  Dordrecht/  Lancaster 


Distributors  for  North  America: 

Kluwer  Academic  Publishers 

101  Philip  Drive 

Assinippi  Park 

Norwell,  Massachusetts  02061,  USA 

Distributors  for  the  UK  and  Ireland: 

Kluwer  Academic  Publishers 

MTP  Press  Limited 

Falcon  House,  Queen  Square 

Lancaster  LAI  1RN,  UNITED  KINGDOM 

Distributors  for  all  other  countries: 

Kluwer  Academic  Publishers  Group 

Distribution  Centre 

Post  Office  Box  322 

3300  AH  Dordrecht,  THE  NETHERLANDS 


Library  of  Congress  Cataloging-in-Publication  Data 

Bromley,  Hank. 
Lisp  lore. 

Includes  index. 

1.  LISP  (Computer  program  language)     I.  Title. 
QA76.73.L23B75     1986  005.133  86-7377 

ISBN  0-89838-220-3 


Copyright  ©  1986  by  Bell  Telephone  Laboratories,  Incorporated.  Portions  of  this  book  are  copyrighted 
by  Symbolics,  Inc. 

All  rights  reserved.  No  part  of  this  publication  may  be  reproduced,  stored  in  a  retrieval  system,  or 
transmitted  in  any  form  or  by  any  means,  mechanical,  photocopying,  recording,  or  otherwise,  without 
the  prior  written  permission  of  the  publisher,  Kluwer  Academic  Publishers,  101  Philip  Drive,  Assinippi 
Park,  Norwell,  Massachusetts  02061. 

Printed  in  the  United  States  of  America 


TABLE  OF  CONTENTS 


LIST  OF  FIGURES 

ix 

PREFACE 

xi 

INTRODUCTION 

1 

GETTING  STARTED  ON  THE  LISP  MACHINE 

5 

1.1     The  Keyboard 

5 

1.2    Typing  to  a  Lisp  Listener 

8 

1.3    Logging  In 

9 

1.4    The  FEP 

10 

1.5    Random  Leftovers:   the  mouse,  the  monitor,  the  editor 

12 

1.6    Problem  Set  #1 

14 

WHAT'S  A  FLAVOR? 

17 

2.1     Basic  Usage 

18 

2.2    Initial  Values  for  Instance  Variables 

20 

2.3    Mixing  Flavors 

22 

2.4    Combined  Methods 

23 

2.5    Other  Ways  of  Combining  Methods 

28 

2.6    Vanilla-flavor 

30 

2.7    Fun  and  Games 

31 

2.8    Problem  Set  #2 

32 

MORE  ON  NAVIGATING  THE  LISP  MACHINE 

43 

3.1     The  scheduler  and  processes 

43 

3.2    Windows 

46 

3.3    Debugging 

50 

3.4    Who  Does  What 

52 

3.5    The  Input  Editor  and  Histories 

53 

3.6    Fun  and  Games 

54 

3.7    Problem  Set  #3 

57 

FLOW  OF  CONTROL 

61 

4.1     Conditionals 

61 

4.2    Blocks  and  Exits 

63 

4.3    Nonlocal  Exits 

64 

4.4    Iteration 

64 

5.1 

The  Nodes  and  Arcs 

5.2 

Managing  Multiple  Windows  and  Processes 

5.3 

The  Windows  and  the  Mouse 

5.4 

Fun  and  Games 

5.5 

The  Program 

5.6 

Problem  Set  #5 

STREAMS  AND  FILES 

6.1 

Streams 

6.2 

Accessing  Files  and  Directories 

6.3 

Pathnames 

6.4 

Fun  and  Games 

6.5 

Problem  Set  #6 

TABLE  OF  CONTENTS 


4.5  A  Bit  More  on  Working  with  Macros  71 

4.6  Fun  and  Games  71 

4.7  Problem  Set  #4  73 

THE  GRAPH  EXAMPLE  83 

84 
85 
87 
91 
91 
101 

119 

119 
125 
129 
135 
137 

7  THE  TREE  EXAMPLE  139 

7.1  The  Nodes  and  Arcs  139 

7.2  The  Windows  and  the  Mouse  141 

7.3  Fun  and  Games  143 

7.4  The  Program  144 

7.5  Problem  Set  #7  155 

8  RANDOM  USEFUL  TOPICS:  RESOURCES  &  SYSTEMS                        161 

8.1  Resources  161 

8.2  Systems  165 

8.3  Problem  Set  #8  170 

9  SIGNALING  AND  HANDLING  CONDITIONS  173 

9.1  Overview  173 

9.2  A  Few  Examples  174 

9.3  More  on  Handlers  176 

9.4  Restart  Handlers  178 

9.5  More  on  Proceeding  179 

10  THE  MOVING  ICONS  EXAMPLE  183 

10.1  General  183 

10.2  moving-icons-frame  185 

10.3  moving-icons-main-pane  185 


TABLE  OF  CONTENTS 


10.4  Messing  with  the  mouse  blinker  186 

10.5  The  :drop-icon  method  187 

10.6  Setting  up  the  comtab  188 

10.7  Getting  in  the  System  Menu  188 

10.8  The  Program  189 

10.9  Problem  Set  #9  194 

1 1  MORE  ADVANCED  USE  OF  THE  EDITOR  199 

11.1  Keyboard  Macros  199 

11.2  Writing  New  Commands  201 

1 1.3  Buffers  and  Streams  201 

1 1.4  Reading  from  the  Mini-buffer  204 

11.5  A  Real  Example  206 

11.6  Problem  Set  #10  207 

12  A  QUICK  LOOK  AT  "THE  NETWORK"  211 

12.1  The  "Gee- Whiz"  Overview  211 

12.2  The  Beginning  of  the  Real  Explanation  213 

12.3  The  Ethernet  214 
12.4Chaosnet  215 

12.5  A  Bit  More  on  Serial  Streams  217 

12.6  The  Role  of  the  Namespace  2 1 7 

12.7  Troubleshooting  219 

APPENDIX:   BASIC  ZMACS  COMMANDS  221 

INDEX  225 


LIST  OF  FIGURES 

1  Flavor  tree  for  lisp-listener  24 

2  Structure  of  combined  method  28 

3  Transitions  among  window  states  48 


PREFACE 


This  book  had  its  genesis  in  the  following  piece  of  computer  mail: 

From  allegra!joan-b  Tue  Dec  18  09:15:54  1984 
To:  solalhjb 
Subject:  lispm 

Hank,  I've  been  talking  with  Mark  Plotnik  and  Bill  Gale  about 
asking  you  to  conduct  a  basic  course  on  using  the  lisp  machine. 
Mark,  for  instance,  would  really  like  to  cover  basics  like  the  flavor 
system,  etc.,  so  he  could  start  doing  his  own  programming  without 
a  lot  of  trial  and  error,  and  Bill  and  I  would  be  interested  in  this, 
too.  I'm  quite  sure  that  Mark  Jones,  Bruce,  Eric  and  Van  would 
also  be  really  interested.  Would  you  like  to  do  it?  Bill  has  let  me 
know  that  if  you'd  care  to  set  something  up,  he's  free  to  meet  with 
us  anytime  this  week  or  next  (although  I'll  only  be  here  on  Wed. 
next  week)  so  we  can  come  up  with  a  plan.  What  do  you  think? 
Joan. 

(All  the  people  and  computers  mentioned  above  work  at  AT&T  Bell  Laboratories, 
in  Murray  Hill,  New  Jersey.)  I  agreed,  with  some  trepidation,  to  try  teaching  such 
a  course.    It  wasn't  clear  how  I  was  going  to  explain  the  lisp  machine  environment 


Xii  PREFACE 


to  a  few  dozen  beginners  when  at  the  time  I  felt  I  was  scarcely  able  to  keep  myself 
afloat.  Particularly  since  many  of  the  "beginners"  had  PhD's  in  computer  science 
and  a  decade  or  two  of  programming  experience.  But  the  need  was  apparent,  and 
it  sounded  like  fun  to  try,  so  we  had  a  few  planning  sessions  and  began  class  the 
next  month. 

From  early  January  through  late  March  we  met  once  a  week,  about  a  dozen  times 
in  all,  generally  choosing  the  topic  for  each  session  at  the  conclusion  of  the  previous 
one.  I  spent  the  last  few  days  before  each  meeting  throwing  together  lecture  notes 
and  a  problem  set  (typically  finishing  shortly  after  the  announced  class  time).  By 
the  end  of  the  course,  the  students  had  attained  varying  levels  of  expertise.  In  all 
likelihood,  the  person  who  learned  the  most  was  the  instructor;  nothing  provides 
motivation  to  figure  something  out  like  having  committed  oneself  to  talking  about 


After  it  was  over,  another  co-worker  saw  the  sizable  pile  of  handouts  I  had  gen- 
erated and  proposed  that  it  would  make  a  good  book.  He  offered  to  contact  a  pub- 
lisher he  had  recently  deaft  with.  I  was  at  first  skeptical  that  the  informal  notes  I 
had  hurriedly  concocted  would  interest  a  reputable  academic  publisher,  but  after 
taking  another  look  at  the  materials  that  had  sprouted,  and  discussing  the  matter, 
we  agreed  that  quite  a  few  people  would  find  them  valuable.  I've  spent  the  last  few 
months  filling  out  and  cleaning  up  the  pile,  and  Presto,  change-o.  My  "set  of  hand- 
outs" is  "a  book." 

There  are  a  number  of  people  who  have,  in  one  way  or  another,  consciously  or  oth- 
erwise, helped  create  this  book.  Ken  Church  was  instrumental  in  arranging  my 
first  experience  using  the  lisp  machine,  and  later  was  responsible  for  bringing  me  to 
Bell  Labs.  He  also  taught  a  course  here,  before  I  came,  which  laid  some  of  the 
groundwork  for  my  own  course.  Eva  Ejerhed,  in  a  rare  act  of  faith,  hired  me  to 
work  on  a  lisp  machine  thousands  of  miles  from  the  nearest  expert  assistance, 
without  my  having  ever  touched  one.  Joan  Bachenko  and  Bill  Gale  first  suggested  I 
teach  a  course  at  the  Labs.  Many  of  my  colleagues  who  served  as  experimental 
subjects  by  participating  in  one  of  the  three  trials  of  the  course  provided  useful 
comments  on  the  class  handouts;  among  those  whose  contributions  I  particularly 
recall  are  Mark  Liberman,  Jeff  Gelbard  and  Doug  Stumberger.  Ted  Kowalski  first 
broached  the  idea  of  making  a  book  from  the  handouts,  and  also  —  with  Sharon 
Murrel  —  supplied  lots  of  assistance  with  the  use  of  their  Monk  text  formatting 
system.  Wayne  Wolf  suggested  improvements  to  my  coverage  of  managing  multi- 
ple processes.    Jon  Balgley,  of  Symbolics,  Inc.,*     wrote  a  helpful  review  of  one 


Symbolics,  Symbolics  3600,  Symbolics  3640,  Symbolics  3670,  and  Document  Examiner  are  trade- 
marks of  Symbolics,  Inc. 
Zetalisp®  is  a  registered  trademark  of  Symbolics,  Inc. 


PREFACE 


Xlll 


version  of  the  manuscript.  Valerie  Barr  introduced  herself  to  the  lisp  machine  by 
actually  working  through  an  entire  draft,  making  a  great  many  valuable  observa- 
tions along  the  way.  Mitch  Marcus  and  Osamu  Fujimura,  my  supervision  at  the 
Labs,  were  most  understanding  about  the  amount  of  time  I  put  into  this  project. 
Carl  Harris  was  an  obliging  and  patient  Publisher.  Finally,  Symbolics,  Inc.  gra- 
ciously allowed  me  to  quote  extensively  from  their  copyrighted  materials,  and 
Sheryl  Avruch  of  Symbolics  made  possible  the  distribution  of  a  tape  to  accompany 
this  book. 

I  would  like  to  hear  about  any  problems  readers  have  while  working  their  way 
through  the  text.  Please  don't  hesitate  to  mail  me  any  of  your  comments  or  sugges- 
tions. 


Hank  Bromley 
December,  1985 


computer  mail: 


US  mail: 


hjb@mit-mc    (arpa) 

AT&T  Bell  Laboratories,  room  2D-410 
alice  600  Mountain  Avenue 

research  }  !sola!hjb    (uucp)       Murray  Hill,  NJ     07974 
allegra 


LISP  LORE:  A  GUIDE  TO 
PROGRAMMING  THE  LISP  MACHINE 


INTRODUCTION 


The  full  1 1 -volume  set  of  documentation  that  comes  with  a  Symbolics  lisp  machine 
is  understandably  intimidating  to  the  novice.  "Where  do  I  start?"  is  an  oft-heard 
question,  and  one  without  a  good  answer.  The  eleven  volumes  provide  an  excellent 
reference  medium,  but  are  largely  lacking  in  tutorial  material  suitable  for  a 
beginner.  This  book  is  intended  to  fill  that  gap.  No  claim  is  made  for  complete- 
ness of  coverage  —  the  eleven  volumes  fulfill  that  need.  My  goal  is  rather  to 
present  a  readily  grasped  introduction  to  several  representative  areas  of  interest, 
including  enough  information  to  show  how  easy  it  is  to  build  useful  programs  on 
the  lisp  machine.  At  the  end  of  this  course,  the  student  should  have  a  clear  enough 
picture  of  what  facilities  exist  on  the  machine  to  make  effective  use  of  the  complete 
documentation,  instead  of  being  overwhelmed  by  it. 

The  desire  to  cover  a  broad  range  of  topics,  coupled  with  the  necessity  of  limiting 
the  amount  of  text,  caused  many  items  to  be  mentioned  or  referred  to  with  little  or 
no  explanation.  It's  always  appropriate  to  look  up  in  the  full  documentation  any- 
thing that's  confusing.  The  manuals  are  perfectly  adequate  reference  materials,  as 
long  as  you  know  what  you  want  to  look  up.  The  point  in  this  text  is  rarely  to 
explain  what  some  specific  function  does  in  isolation  —  that's  what  the  manuals  are 
good  for.  The  focus  here  is  on  how  to  integrate  the  isolated  pieces  into  real  appli- 
cations, how  to  find  your  way  around  the  landscape,  how  to  use  the  multitudinous 
features  described  in  such  splendid  detail  in  the  1 1  volumes.    The  manuals  provide 


INTRODUCTION 


a  wonderfully  thorough,  but  static,  view  of  what's  in  the  lisp  machine  environment; 
I've  tried  to  provide  a  dynamic  view  of  what  that  environment  looks  like  in  action, 
or  rather  in  interaction  with  a  human. 

The  book  assumes  some  background  in  lisp;  the  reader  is  expected  to  have  experi- 
ence with  some  dialect  of  the  language.  If  you  lack  such  experience,  you  may  want 
to  do  a  bit  of  preparatory  study.*  This  course  concentrates  on  those  aspects  of  lisp 
machine  lisp  ("Zetalisp")  which  are  not  found  in  most  dialects,  and  on  the  unique 
overall  programming  environment  offered  by  the  lisp  machine.  No  experience  with 
the  lisp  machine  itself  is  assumed. 

Finding  an  ideal  order  of  presentation  for  the  various  topics  would  be  difficult. 
Many  topics  are  interdependent,  such  that  knowing  either  would  help  in  figuring 
out  the  other.  Presenting  them  simultaneously  would  only  confuse  matters,  so  I've 
had  to  settle  on  one  particular  linear  sequence  of  topics.  It  may  seem  natural  to 
some  readers  and  bizarre  to  others.  I've  tried  to  identify  places  where  it  might  be 
helpful  to  look  ahead  at  sections  further  on  in  the  text,  but  I'm  sure  I  haven't  found 
them  all,  so  don't  hesitate  to  engage  in  a  little  creative  re-ordering  if  you  feel  the 
urge.  One  chapter  whose  position  is  problematic  is  that  on  flavors.  Conceptually,  it 
is  probably  more  difficult  than  both  of  the  two  subsequent  chapters  {More  on  Navi- 
gating the  Lisp  Machine  and  Flow  of  Control).  But  I've  chosen  to  put  it  first 
because  the  flavor  system  is  extremely  characteristic  of  lisp  machine  programming, 
making  it  important  to  discuss  as  soon  as  possible.  The  main  barrier  to  mastering 
the  lisp  machine  is  absorbing  its  gestalt,  much  of  which  is  implicit  in  the  flavor  sys- 
tem; covering  that  right  at  the  beginning  helps  to  set  the  tone  for  what  follows.  But 
if  you  find  flavors  a  bit  much,  feel  free  to  look  through  Navigating  and  maybe  Flow 
of  Control  and  come  back  to  it. 

I've  adopted  a  rather  informal  tone  for  most  of  the  text:  people  learn  better  if 
they're  relaxed.  Just  let  me  caution  you  that  "informal"  doesn't  mean  "sloppy." 
There  are  few  extra  words.  Lots  of  information  is  present  in  only  one  place,  and 
apparent  only  if  you  read  carefully.  If  you  get  fooled  by  the  informality  into  think- 
ing you  can  scan  half-attentively,  you'll  miss  things. 

It  must  be  emphasized  that  learning  to  use  the  lisp  machine  is  more  a  matter  of 
learning  a  way  of  thinking  than  of  learning  a  set  of  specific  programming  con- 
structs. No  amount  of  time  spent  studiously  poring  over  documentation  can  yield 
the  benefits  gained  from  sitting  at  a  console  and  exploring  the  environment  directly. 


Two  widely  available  sources  you  may  find  well  worth  your  time  are  Lisp  (2nd  edition),  Winston  and 
Horn,  Addison- Wesley,  1984,  and  Structure  and  Interpretation  of  Computer  Programs,  Abelson  and 
Sussman,  MIT  Press,  1984. 


INTRODUCTION 


Time  spent  examining  various  parts  of  the  system  software  with  no  particular  goal 
in  mind  is  anything  but  wasted.  Once  one  has  a  feel  for  how  things  are  done,  an 
overview  of  how  things  fit  together,  the  rest  will  follow  easily  enough.  Most  lisp 
machine  wizards  are  self-taught;  the  integrated  nature  of  the  environment,  and 
ready  access  to  the  system  code,  favors  those  who  treat  learning  the  machine  as  an 
interactive  game  to  play. 

With  that  in  mind,  a  word  or  two  of  advice  on  the  problem  sets.  Don't  get  too 
wrapped  up  in  finding  the  "right  answer."  Many  of  the  problems  are,  shall  we  say, 
"challenging;"  they  require  knowledge  not  found  in  the  text  (and  in  some  cases  not 
even  found  in  the  manuals).  You  will  need  to  investigate,  often  without  knowing 
exactly  what  you're  looking  for.  If  the  investigation  fails  to  yield  immediate  results, 
I  strongly  recommend  that  rather  than  head  straight  for  my  solutions,  you  continue 
to  investigate.  Stick  it  out  for  a  while,  even  if  you  don't  seem  to  be  getting  much 
closer.  You  can't  learn  to  speak  a  foreign  language  by  consulting  a  dictionary 
every  time  you  need  a  word  you  don't  know  —  forcing  yourself  to  improvise  from 
what  you  do  know  is  the  only  way.  Floundering  is  an  unpleasant  but  absolutely 
necessary  part  of  the  process,  arguably  the  only  part  during  which  you're  really 
learning.  Similarly,  you  can't  become  a  lisp  wiz  just  by  assiduously  studying  some- 
one else's  code.  Although  seeing  how  an  experienced  programmer  handles  a  prob- 
lem is  certainly  useful,  it's  no  substitute  for  struggling  through  it  yourself.  The 
problem  sets  are  largely  a  ruse  to  get  you  mucking  around  on  the  machine.  I  don't 
really  care  if  you  solve  them,  as  long  as  you  come  up  with  some  ideas  and  try  them 
out  with  an  open  mind. 

The  examples  in  the  text  (barring  typos)  are  known  to  work  in  Release  6.1  of  the 
Symbolics  software  for  the  3600  family  of  machines.  Only  the  "moving  icons" 
example  requires  additional  support  software  not  included  in  the  text.  That 
software  is  available  on  a  cartridge  tape,  which  also  contains  all  the  code  for  the 
"graph,"  "tree,"  and  "moving  icons"  examples,  as  it  appears  here,  and  all  problem 
solutions  which  are  too  long  to  reasonably  be  manually  copied  from  the  text. 

To  order  a  copy  of  the  tape,  write  to  the  following  address  (you  may  wish  to  use 
the  order  form  at  the  back  of  this  book)  and  include  a  check  for  $40  made  out  to 
Symbolics,  Inc.    Instructions  for  loading  the  tape  will  accompany  it. 

Software  Release 
Symbolics,  Inc. 
1 1  Cambridge  Center 
Cambridge,  MA   02142 


Chapter    1 

GETTING   STARTED  ON  THE  LISP  MACHINE 


1.1  The  Keyboard 

Note  that  there  are  many  keys  which  don't  appear  on  a  standard  keyboard.  Much 
of  what  you  need  to  know  to  start  using  a  Lisp  Machine  boils  down  to  knowing 
what  the  various  funny  keys  do. 

Apart  from  the  keys  for  the  standard  printing  characters  (white  labels  on  grey 
keys),  there  are  two  kinds  of  special  keys.  The  beige  keys  with  grey  labels  (shift, 
control,  meta,  super,  hyper,  and  symbol)  are  all  used  like  the  shift  key  —  you  hold 
them  down  while  striking  some  other  key.  These  modifier  keys  may  be  used  singly 
or  in  combination.  So  "control-meta-K"  means  type  K  while  holding  down  control 
and  meta.  There  is  a  standard  set  of  abbreviations  for  the  various  modifier  keys. 
They're  all  just  what  you'd  expect  except  that  the  abbreviation  s  stands  for  super 
rather  than  shift.   Shift  is  abbreviated  sh. 

The  beige  keys  with  white  labels  are  special  function  keys,  and  are  typed  like  stan- 
dard printing  characters.  That  is,  "Select-E"  means  to  strike  Select  and  then  strike 
E.  And  "Select  c-L"  means  to  strike  Select  and  then  hold  down  control  and  strike 
L. 


GETTING  STARTED  ON  THE  LISP  MACHINE 


Chapter  1 


Use  the  Help  key  a  lot.  The  information  it  supplies  depends  on  the  context,  but  it 
usually  tells  you  what  sort  of  input  is  wanted  by  the  program  you're  typing  to. 

You  can  think  of  the  Lisp  Machine  as  a  collection  of  processes,  analogous  to  the 
different  users  on  a  time-sharing  system.  Each  process  is  a  program  written  in  lisp 
and  running  in  a  common  environment  which  all  the  processes  share.  A  process 
typically  (but  not  necessarily)  has  a  window  for  user  interaction.  The  Select  key  is 
the  easiest  way  to  switch  among  processes.  To  find  out  what  your  options  are,  type 
Select-Help.  The  display  shows  you  that,  among  other  programs  that  may  be 
reached  in  this  way,  you  can  get  a  lisp  listener  by  typing  Select-L,  and  an  editor  by 
typing  Select-E.  This  list  is  by  no  means  fixed.  Users  may  add  their  own  programs 
to  the  list  quite  easily.  Here  are  brief  descriptions  of  the  programs  that  are  already 
in  the  select  list  on  a  freshly  booted  lisp  machine: 


X        Common  Lisp 
C        Converse 


D  Document  Examiner 

E  Editor 

F  File  System  Maintenance 

I  Inspector 

L  Lisp 

M  Zmail 

N  Notifications 

P  Peek 

T  Terminal 

X  Flavor  Examiner 


a  (Common  Lisp)  lisp  listener  [X  =  symbol-sh-L] 
convenient  way  to  send  and  receive  messages 
from  users  currently  logged-in  on  other  machines 
(lisp  or  otherwise) 

a  utility  for  finding  and  reading  online  documen- 
tation; everything  in  the  11 -volume  manual  is 
available  here 

the  powerful  Zmacs  editor,  like  Emacs  plus 
much  more 

various  display  and  maintenance  operations  on 
the  file  system  of  the  lisp  machine  or  of  other 
machines 

structure  editor  for  displaying  and  modifying  lisp 
objects 

a  (Zetalisp)  lisp  listener 

a  comprehensive  mail-reading  and  sending  pro- 
gram, using  many  pieces  of  the  Zmacs  editor 
displays  a  list  of  all  "notifications"  (messages 
from  running  programs)  you've  received 
displays  the  status  of  various  aspects  of  the  lisp 
machine 

use  the  lisp  machine  as  a  terminal  to  log  in  to 
other  computers 

convenient  way  to  find  out  about  different  flavors 
(active  objects),  their  message-handlers,  and 
their  state  variables. 


The  Function  key,  like  Select,  dispatches  off  the  following  keystroke.    Function- 


Section  1.1  The  Keyboard 


Help  displays  a  list  of  the  options.  The  most  commonly  used  are  Function-F 
("finger"),  to  find  out  who's  logged  in  on  the  various  machines,  Function-H  ("hos- 
tat"),  for  a  quick  look  at  the  status  of  all  the  hosts  on  the  local  Chaosnet,  and 
Function-S  to  select  a  different  window.  The  exact  behavior  of  many  of  the  Func- 
tion options  is  controlled  by  an  optional  numeric  argument;  you  pass  the  argument 
by  pressing  one  of  the  number  keys  after  the  Function  key  and  before  the  chosen 
letter,  e.g.,  Function-O-S. 

The  Suspend  key  generally  causes  the  process  you  are  typing  to  to  enter  a  "break 
loop",  that  is,  the  state  of  its  computation  is  suspended  and  a  fresh  read-eval-print 
loop  is  pushed  on  top  of  the  current  control  stack.  The  Resume  key  will  continue 
the  interrupted  computation.  Suspend  takes  effect  when  it  is  read,  not  when  it  is 
typed.  If  the  program  isn't  bothering  to  check  for  keyboard  input,  pressing 
Suspend  will  do  nothing. 

c -Suspend  does  the  same  thing  as  Suspend,  but  always  takes  effect  immediately, 
regardless  of  whether  the  program  is  looking  for  keyboard  input. 

m-Suspend,  when  read,  forces  the  process  at  which  you  type  it  into  the  debugger. 
The  debugger  is  another  story  (see  below),  but  when  you're  done  looking  around 
you  can  continue  the  interrupted  computation  with  Resume. 

c-m-Suspend  is  a  combination  of  c-Suspend  and  m-Suspend.  It  immediately  forces 
the  current  process  into  the  debugger. 

The  Abort  key  is  used  to  tell  a  program  to  stop  what  it's  doing.  The  exact  behavior 
depends  on  what  program  you're  typing  to.  A  lisp  listener,  for  instance,  will 
respond  by  throwing  back  to  the  nearest  read-eval-print  loop  (the  top  level  or  an 
intervening  break  loop).  Like  Suspend,  Abort  only  takes  effect  when  read.  If  the 
program  isn't  waiting  for  keyboard  input,  you  need  to  use  c- Abort  instead. 

m- Abort,  when  read,  throws  out  of  all  levels  and  restarts  the  top  level  of  the  pro- 
cess,  c-m- Abort  has  this  effect  immediately. 

The  debugger  prompt  is  a  small  right-pointing  arrow.  Once  you  have  that,  all 
kinds  of  commands  are  available  for  moving  up  and  down  the  stack,  getting  infor- 
mation about  the  different  frames  on  the  stack,  restarting  execution  with  or  without 
modifying  arguments  and  variable  values,  etc.  Try  the  Help  key  and  see  what  you 
can  find  out.  Besides  all  the  special  commands,  any  normal  text  you  type  will  be 
evaluated  by  the  lisp  interpreter. 


GETTING  STARTED  ON  THE  LISP  MACHINE  Chapter  1 


1.2  Typing  to  a  Lisp  Listener 

A  lisp  listener  is  a  window  with  a  lisp  interpreter  running  in  it.  It  reads  a  lisp 
expression  from  the  keyboard,  evaluates  it,  prints  the  returned  value (s),  and  waits 
for  another  expression.  Booting  a  machine  leaves  you  in  a  lisp  listener.  Whenever 
you're  not  in  a  lisp  listener  you  can  get  to  one  by  typing  Select-L. 

While  waiting  for  input,  lisp  listeners  usually  display  "Command:"  as  a  prompt. 
The  presence  of  this  prompt  indicates  that  the  Command  Processor  (CP)  is  active; 
it  provides  a  convenient  interface  to  many  frequently  called  lisp  functions.  (The 
name  of  a  CP  command  won't  necessarily  be  the  same  as  the  name  of  the 
corresponding  lisp  function.)  CP  commands  don't  use  the  same  parentheses  syntax 
as  lisp  expressions  do.  You  simply  type  the  name  of  the  command  (one  or  more 
words)  followed  by  any  arguments  to  the  command,  and  finish  with  the  Return  key. 
But  you  needn't  type  the  name  of  the  command  in  its  entirety  —  all  that's  required 
is  enough  to  uniquely  identify  which  command  you  mean.  The  CP  command 
Help  (i.e.,  type  out  the  letters  h,  e,  1,  p,  and  hit  Return)  lists  all  the  defined  com- 
mands. Pressing  the  Help  key  while  partway  through  a  command  will  display  a  list 
of  only  those  commands  which  match  your  input  thus  far.  Section  3.2  in  volume  1 
of  the  documentation  describes  all  the  CP  commands  present  in  the  software  distri- 
buted by  Symbolics.  You  can  define  more  of  your  own.  One  command  which  may 
be  particularly  valuable  to  new  users  is  Show  Documentation.  You  specify 
some  topic  you  want  looked  up  in  the  manuals  and  it  displays  a  facsimile  of  that 
portion  of  the  documentation  on  your  screen. 

You  may  be  wondering  how  the  command  processor  knows  whether  you  intend 
your  typein  to  be  interpreted  as  a  CP  command  or  as  a  lisp  expression.  If  you 
begin  with  a  letter,  it  assumes  you're  starting  a  CP  command;  with  a  non- 
alphabetic  initial  character  it  tries  to  parse  your  input  as  a  lisp  expression.  Since 
lisp  expressions  usually  begin  with  a  left  paren,  it  guesses  correctly  most  of  the 
time.  But  what  if  you  want  to  evaluate  a  lisp  symbol  —  if  the  symbol's  name 
begins  with  a  letter,  the  command  processor  will  guess  wrong  and  look  for  a  com- 
mand with  that  name.  The  solution  here  is  to  type  a  comma  before  the  symbol's 
name.  The  comma  has  special  meaning  for  the  command  processor:  it  forces 
whatever  follows  to  be  interpreted  as  a  lisp  expression,  regardless  of  what  the  initial 
character  is. 

If  you'd  like  to  know  about  some  other  features  that  are  available  whenever  you're 
typing  to  a  lisp  listener  and  you  don't  already  feel  as  though  you've  seen  more  than 
you  can  possibly  remember,  I  suggest  looking  ahead  at  the  section  "The  Input  Edi- 
tor and  Histories"  in  chapter  3.  It'll  make  life  much  easier  as  you  take  on  the  first 
few  problem  sets. 


Section  1.2  Typing  to  a  Lisp  Listener 


1.3  Logging  In 

To  login,  you  simply  use  the  CP  command  Login  with  an  argument  of  your  user- 
id.  In  my  case,  it  looks  like  Login  hjb.  Alternatively,  you  could  apply  the  lisp 
function  "login"  to  your  user-id:  (login  'hjb).  The  effect  is  the  same,  but  the 
former  requires  less  typing  (because  of  the  automatic  command  completion).  The 
only  reason  I  sometimes  use  lisp  functions  when  there  is  an  equivalent  CP  com- 
mand is  force  of  habit:  the  command  processor  is  a  fairly  new  feature,  while  my 
fingers  have  been  typing  the  lisp  functions  for  years. 

It's  important  to  keep  in  mind  the  difference  between  a  local  login  to  the  lisp 
machine,  and  remote  logins  to  other  machines  being  used  as  file  servers.  Local 
logins  are  controlled  by  a  database  called  the  namespace.  To  login  locally  with  a 
certain  user-id  requires  that  there  be  an  entry  in  the  namespace  for  that  user-id.  It 
does  not  require  a  password,  as  there  is  no  internal  security  on  the  lisp  machine. 

Many  things  on  the  lisp  machine  can  be  done  with  no  one  logged  in.  Some  opera- 
tions, however,  do  require  that  someone  be  logged  in.  Modifying  the  namespace, 
for  instance,  is  one  of  these  operations.  How,  then,  you  may  ask,  do  you  create  a 
namespace  entry  for  yourself  if  you  can't  modify  the  namespace  unless  you're 
logged  in,  and  you  can't  log  in  unless  you're  in  the  namespace?  One  option  would 
be  to  log  in  as  someone  else  so  you  can  create  a  namespace  entry  for  yourself,  and 
then  log  in  as  yourself.  But  nothing  so  underhanded  is  really  necessary.  All  lisp 
machines  have  a  dummy  user  in  the  namespace  which  the  system  itself  uses  when  it 
needs  to  do  something  which  requires  having  someone  logged  in.  (This  situation 
arises  most  notably  while  the  machine  is  being  booted  —  no  one  can  log  in  until  it's 
finished  booting,  but  it  can't  finish  booting  until  it  does  a  bunch  of  things  that 
require  someone  being  logged  in.)  The  dummy  user  is  typically  named  "Lisp 
Machine",  with  user-id  "Lispm"  or  "NIL".  Whatever  it's  called  on  your  machine, 
you  can  always  use  it  by  typing  ( si:  login-to-sys-host).  This  is  often  a 
handy  trick  to  know  about.  You  can  now  edit  the  namespace  —  use  the  CP  com- 
mand Edit  Namespace  Object  —  and  create  a  user  object  for  yourself.  There 
is  introductory  documentation  on  the  namespace  and  the  namespace  editor  in 
chapter  11  of  volume  1. 

Whenever  you  log  in  to  a  lisp  machine,  unless  you  explicitly  specify  otherwise,  it 
tries  to  find  your  personal  initialization  file  and  load  it  into  the  lisp  environment. 
This  is  a  file  containing  any  number  of  lisp  forms  which  customize  the  machine  for 
you.  They  will  typically  set  some  variable  values  and  load  some  other  files.  Where 
the  machine  looks  for  your  init  file  depends  on  what  you  specified  for  your  home 
host   in   your   namespace  entry.     If  you   specified   a   host   running   the  UNIX* 


10  GETTING  STARTED  ON  THE  LISP  MACHINE  Chapter  1 


operating  system,  it  will  first  look  for  a  file  named  lispm-init  .bn  in  your  direc- 
tory on  that  machine.  If  your  home  host  is  a  lisp  machine,  it'll  look  for  the  newest 
version  of  a  file  named   lispm-init.bin. 

The  issue  of  remote  logins  arises  whenever  you  try  to  do  something  from  the  lisp 
machine  on  another  computer  across  a  network,  like  read  or  write  a  file.  If  the 
remote  host  is  a  lisp  machine,  it  won't  ask  for  a  password,  and  your  local  machine 
can  take  care  of  establishing  the  connection  with  no  intervention  on  your  part.  But 
if  the  remote  host  is  the  sort  that  believes  in  security,  say  a  UNIX  system,  it'll  stop 
your  local  machine  from  doing  anything  until  you  provide  an  appropriate  login  id 
and  password.  Your  local  machine  will  pass  the  request  right  along  to  you.  But 
it's  essentially  a  matter  between  you  and  the  remote  host  —  the  local  machine 
doesn't  care  what  username  you  use  on  the  remote  machine,  or  whether  it's  one 
that  exists  in  the  namespace.  The  local  machine  is  just  a  messenger  in  this  case.  It 
will,  however,  try  to  be  helpful.  If  you  specify  in  your  namespace  entry  what  user- 
names  you  want  to  use  on  the  various  remote  hosts,  the  local  machine  will  try  those 
first,  even  if  those  names  are  arbitrary  nonsense  as  far  as  the  local  machine  can  tell. 
And  you  can  always  override  the  default  usernames. 

And  while  we're  on  remote  file  systems,  there's  the  question  of  whether  you  should 
keep  your  files  on  a  lisp  machine  or  some  other  sort  of  file  server.  It  depends  on 
what  sort  of  set-up  you  have  —  how  much  disk  space  in  what  places,  how  many 
users,  etc.  It's  often  the  case  that  you'll  want  to  keep  as  few  files  as  possible  on  the 
lisp  machine  disks,  because  the  available  space  would  be  better  utilized  by  virtual 
memory  and  saved  lisp  worlds.  Files  can  be  kept  on  any  machine  you  have  an  eth- 
ernet  connection  to,  with  little  loss  of  efficiency,  so  large  file  systems  are  effectively 
dead  weight  on  a  lisp  machine.  If  at  all  practical  it  makes  more  sense  to  convert 
every  available  megabyte  to  virtual  memory  or  room  for  saved  worlds,  which  have 
to  be  on  the  local  disk. 


1.4  The  FEP 

Having  looked  at  the  disk  label  brings  up  the  Front-End  Processor,  or  FEP.  The 
Fep  is  a  68000-based  computer  which  handles  starting  up  the  main  processor  of  the 
lisp  machine,  and  may  also  become  active  if  the  lisp  machine  enters  an  illegal  state, 
whether  because  of  a  hardware  malfunction  or  system-software  bug.  You  can  tell 
if  your  lisp  machine  is  in  the  Fep  if  there's  a  prompt  that  looks  like  this:  "Fep>", 
and  the  clock  at  the  lower  left  of  the  screen  has  stopped.  For  now,  there  are  just 
three  Fep  commands  you  should  know.    Continue,  which  may  be  shortened  to 


UNIX  is  a  trademark  of  AT&T  Bell  Laboratories. 


Section  1.4  The  FEP  11 


"con",  tells  the  Fep  to  try  having  the  lisp  machine  resume  exactly  where  it  left  off. 
If  you  were  thrown  into  the  Fep  because  of  some  serious  system  error,  this  is  not 
likely  to  work  —  you  will  probably  be  thrown  right  back  into  the  Fep.  But  not 
always.  Start,  which  may  be  shortened  to  "st",  does  a  warm  boot.  It  tries  to  re- 
start all  of  the  machine's  active  processes  while  preserving  the  state  of  the  lisp 
environment  (i.e.,  function  and  variable  bindings).  This  is  a  something  of  a 
kludge.*  It  can  put  things  into  an  inconsistent  state,  and  is  something  of  a  last 
resort,  but  it  is  sometimes  the  only  way  to  get  a  wedged  machine  going  again,  short 
of  wiping  the  environment  clean,  and  losing  whatever  work  was  in  progress.  That  is 
the  effect  of  the  Fep  command  Boot,  which  may  be  shortened  to  "b".  Boot  does  a 
cold  boot.  It  clears  the  machine's  memory,  reloads  the  microcode,  restores  one  of 
the  saved  worlds  into  the  virtual  memory,  and  does  a  start.  This  is  how  you  get  a 
fresh  machine. 

There  are  times  when  you  may  want  to  get  into  the  Fep  so  you  can  do  a  warm  or 
cold  boot.  Perhaps  your  machine  has  been  used  by  someone  else  who  has 
significantly  changed  the  lisp  environment  in  unfamiliar  ways,  or  who  has  used  up 
nearly  all  your  virtual  memory.  Then  you  will  likely  want  to  do  a  cold  boot.  Or 
perhaps,  as  often  happens  to  me,  you  were  playing  with  some  critical  part  of  the 
system  code  (after  all,  it's  written  in  lisp  and  is  completely  accessible),  did  some- 
thing unwise,  and  now  your  machine  is  wedged,  responding  neither  to  keyboard 
input  nor  mouse  clicks.  Then  you  may  wish  to  resort  to  a  warm  boot,  and  salvage 
what  you  can.  So  to  get  into  the  Fep,  the  preferred  method  is  to  use  the  CP  com- 
mand Halt  Machine  [or  evaluate  (si: halt)].  That'll  do  it.  But  if  your 
machine  isn't  responding  to  the  keyboard,  typing  a  command  isn't  an  option.  Then 
you'll  have  to  use  hyper-control- Function.  Yes,  if  you  hold  down  hyper  and  control 
and  type  Function,  your  lisp  machine  will  enter  the  Fep  under  any  conditions  other 
than  hardware  failure.  This  is  not  the  preferred  method  because  the  lisp  processor 
will  be  rather  rudely  interrupted  and  may  leave  things  in  an  inconsistent  state.  But 
if  all  else  fails,  it  is  the  appropriate  action. 


KLUGE,  KLUDGE  (Jclooj)  noun. 

1 .  A  Rube  Goldberg  device  in  hardware  or  software. 

2.  A  clever  programming  trick  intended  to  solve  a  particularly  nasty  case  in  an  efficient,  if  not 
clear,  manner.   Often  used  to  repair  BUGS.   Often  verges  on  being  a  CROCK. 

3.  Something  that  works  for  the  wrong  reason. 

4.  verb.  To  insert  a  kluge  into  a  program.   "I've  kluged  this  routine  to  get  around  that  weird  bug, 
but  there's  probably  a  better  way."   Also  "kluge  up." 

5.  A  feature  that  is  implemented  in  a  RUDE  manner. 

(The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  at.  Harper  &  Row,  Publishers,  New  York,  1983.) 


12  GETTING  STARTED  ON  THE  LISP  MACHINE  Chapter  1 


1.5  Random  Leftovers:   the  mouse,  the  monitor,  the  editor 

A  few  observations  on  the  mouse.  The  functions  associated  with  clicking  the  mouse 
buttons  are  completely  context-dependent.  It's  up  to  the  window  the  mouse  is  over 
when  you  click.  It  is  generally  the  case,  though,  that  the  current  binding  of  the 
buttons  will  be  documented  in  the  reverse  video  line  near  the  bottom  of  the  screen. 
And  it  is  also  generally  the  case  that  clicking  once  on  the  left  button  will  select  the 
window  the  mouse  is  pointing  to,  and  clicking  twice  on  the  right  button  will  get  you 
to  the  system  menu.  The  system  menu  offers  many  useful  operations,  such  as 
creating  windows,  moving  and  reshaping  existing  windows,  selecting  some  of  the 
programs  which  are  accessible  via  the  Select  key,  and  some  which  are  not,  etc. 
Play  with  it.  It's  a  very  good  habit  to  keep  an  eye  on  the  mouse  documentation 
line. 

There  is  also  a  lot  of  other  useful  information  available  at  the  bottom  of  the  screen. 
From  left  to  right,  we  have  the  date  and  time;  the  user-id  of  the  currently  logged  in 
user,  if  any;  the  current  package  (the  set  of  all  symbols  is  partitioned  into  pack- 
ages, to  minimize  name  conflicts  —  a  cold-booted  machine  starts  out  in  the  "user" 
package,  which  is  where  you'll  probably  do  most  of  your  work  at  the  beginning); 
the  state  of  the  current  process  ("Tyi"  means  awaiting  keyboard  input);  and  all 
the  way  on  the  right,  the  names  of  any  files  that  are  open  for  reading  or  writing,  or 
a  notice  of  what  services  have  been  invoked  locally  by  some  other  machine.  And 
underneath  the  line  of  text  you  can  sometimes  see  a  few  thin  horizontal  lines. 
These  are  the  run  bars.  The  one  immediately  under  the  process  state  goes  on  when 
some  process  is  actively  running.  The  one  a  bit  to  the  left  of  that,  midway  between 
the  process  state  and  the  current  package,  indicates  that  you  are  paging,  waiting 
for  something  to  be  brought  in  from  disk.  The  other  two  run  bars,  which  appear 
under  the  current  package,  you  will  see  less  often.  They  are  related  to  garbage  col- 
lection. 

One  last  bit  of  information  on  the  monitor.  We  have  some  lisp  machines  which  are 
3600  models,  and  some  which  are  newer  3670s.  The  two  models  are  quite  close  in 
most  respects.  One  way  in  which  they  differ  is  how  the  brightness  of  the  display  is 
controlled.  The  3600  monitors  have  a  knob  on  the  bottom  side  of  the  console 
cabinet,  in  the  front  right  corner.  To  adjust  the  brightness  of  a  3670,  hold  down 
the  Local  key  and  press  "B"  for  brighter  or  "D"  for  dimmer.  (3640s  are  like 
3670s  in  this  respect.) 

The  Zmacs  editor.  The  built-in  editor  commands  are  multitudinous,  and  the  total 
number  of  available  commands  is  continually  growing  because  it's  fairly  easy  and 
very  tempting  to  add  new  ones.  The  Appendix  lists  the  most  basic  commands,  but 
by  far  the  best  way  to  find  out  what's  around  is  to  get  used  to  using  the  online 


Section  1.5  Random  Leftovers:   the  mouse,  the  monitor,  the  editor  13 


documentation.  Some  aspects  of  the  lisp  machine  can  be  mastered  by  reading  the 
manuals,  but  the  editor  is  not  one  of  them.  Type  Help  to  an  editor  window,  and 
type  Help  again.  Start  exploring.  The  most  commonly  helpful  of  the  help  options 
are  A  (Apropos),  C  (Command),  and  D  (Describe).  To  get  started,  use  Help -C  on 
c-X  c-F  and  on  c-X  c-S.  You  should  also  try  Help-A  on  "compile."  And  one  of 
the  best  sources  of  information  on  the  lisp  machine  is  the  m-.  command  (meta- 
period).  It  prompts  for  the  name  of  something,  then  finds  the  file  where  whatever 
you  typed  is  defined.  The  something  is  often  a  function,  but  it  can  also  be  many 
other  kinds  of  lisp  objects:  a  global  variable,  a  flavor,  a  resource...  Two  other  very 
useful  features  of  the  editor  that  you  might  not  run  into  right  away  are  these:  if 
you  type  Suspend,  you  get  a  lisp  listener  which  starts  at  the  top  of  the  screen  and 
grows  as  you  need  it.  This  funny  window  is  called  the  typeout-window.  Resume 
returns  to  the  editor.  And  m-X  Dired,  which  is  also  invoked  by  c-X  D,  is  a  utility 
for  editing  directories.  Call  it  on  some  directory  and  type  Help.  (Keep  in  mind 
that  if  it's  a  lisp  machine  directory,  there's  no  security  to  keep  you  from  deleting 
absolutely  anything.) 


14  GETTING  STARTED  ON  THE  LISP  MACHINE  Chapter  1 


1.6  Problem  Set  #1 

Questions 

This  "problem  set"  is  really  just  a  sample  programming  session,  to  familiarize  you 
with  basic  operations  on  the  lisp  machine. 

1 .  Create  a  namespace  entry  for  yourself. 

2.  Log  in. 

3.  Switch  to  the  editor  and  create  an  empty  buffer  for  a  file  in  your  home  direc- 
tory named  "fact.lisp"  (if  your  home  directory  is  on  a  lisp  machine)  or 
"fact.l"  (if  your  home  directory  is  on  a  UNIX  machine  with  a  14  character 
limit  on  file  names). 

4.  Enter  the  text  for  a  function  named  "fact"  which  returns  the  factorial  of  its 
argument. 

5.  Compile  the  function  from  the  editor  with  c-sh-C,  and  test  it  from  the 
typeout  window. 

6.  When  you're  satisfied  with  the  function's  performance,  save  the  buffer  and 
compile  the  resulting  file. 

7.  Cold  boot  the  machine. 

8.  Log  in,  and  note  that  the  function  "fact"  is  now  undefined. 

9.  Load  the  compiled  version  of  your  file. 
10.   Run  your  function  successfully. 


Section  1.6  Problem  Set  #1  15 


Solutions 

1.  (si:login-to-sys-host),  then  Edit  Namespace  Object.  Click  on 
"create,"  click  on  "user,"  enter  your  chosen  login-id,  fill  in  the  required  fields 
(marked  with  *),  if  you  wish  fill  in  the  optional  fields,  click  on  "save,"  click 
on  "quit." 

2.  Login  yourid 

3.  Select-E,  c-X  c-F  fact,  lisp  (or  fact.l) 

4.  (defun  fact  (n) 

(if  (zerop  n) 
1 
(*  n  (fact  (1-  n)))) ) 

5.  Type  c-sh-C  while  anywhere  inside  the  text  of  the  function  to  compile  it. 
Then  hit  the  Suspend  key  to  get  to  the  typeout  window,  and  evaluate  ( fact 
5 ).   The  Resume  key  returns  to  the  editor  window. 

6.  c-X  c-S,  Meta-X  Compile  File  (Actually,  if  you  skip  the  c-X  c-S,  Compile 
File  will  ask  if  you  want  the  buffer  saved  first.) 

7.  Suspend  or  Select-L,  then  Halt  Machine.  Type  b  (then  Return)  to  the 
Fep  prompt. 

8.  Login  yourid,  then    (fact   5) 

9.  (load  "host :  >dir>subdir>f  act" )  for  a  lisp  machine, 
( load   "host :  //dir//subdir//f  act"  )  for  a  UNIX  host. 

10.    (fact   5) 


Chapter   2 

WHAT'S  A  FLAVOR? 


(For  a  more  detailed  presentation  of  this  material,  see  Part  X,  Flavors,  in  volume  2 
of  the  Symbolics  documentation.  I  have  skipped  many  features  of  flavors  which 
you  may  find  useful,  and  which  are  fully  described  there.) 

The  flavor  system  is  the  lisp  machine's  mechanism  for  denning  and  creating  active 
objects,  that  is,  objects  which  can  receive  messages  and  act  on  on  them.  A  flavor  is 
a  class  of  active  objects.   One  such  object  is  called  an  instance  of  that  flavor. 

There  are  two  primary  characteristics  of  a  flavor:  the  set  of  messages  an  instance 
of  that  flavor  can  receive,  and  the  set  of  state  variables  an  instance  of  that  flavor 
has.  The  state  variables  are  called  instance  variables.  Every  object  of  a  given 
flavor  has  the  same  set  of  instance  variables,  but  the  values  of  those  instance  vari- 
ables are  likely  to  vary  from  object  to  object.  And  for  each  message  a  flavor  can 
receive,  it  has  a  corresponding  function  to  invoke.  The  function  which  gets  called 
to  handle  a  particular  message  is  called  the  flavor's  method  for  that  message.  That 
method  is  shared  by  all  instances  of  the  flavor. 

So,  for  instance,  the  window  you  see  on  a  freshly  booted  machine  is  an  instance  of 
the  flavor  tv:lisp-listener     Like  any  instance  of  lisp-listener,  it  can  handle  286 


18  WHAT'S  A  FLAVOR?  Chapter  2 


different  messages  (as  of  the  current  software).  One  of  the  messages  it  handles  is 
:  expose.  Its  expose  method  is  a  function  which  makes  the  lisp-listener  visible  on 
your  screen,  if  it  is  not  already.  All  lisp-listeners  have  the  same  expose  method. 
One  of  the  instance  variables  of  flavor  lisp-listener  is  exposed-p.  All  lisp- 
listeners  have  an  exposed-p  instance  variable.  If  a  given  lisp-listener  happens  to  be 
exposed,  perhaps  because  you  just  sent  it  the  :expose  message,  the  value  of  its 
exposed-p  instance  variable  will  be  t.   Otherwise  it  will  be  nil. 


2.1  Basic  Usage 

Flavors  are  defined  with  the  defflavor  special  form.  Here  is  a  simple  definition  of  a 
flavor  named  "ship,"  which  might  be  used  in  a  program  for  a  space  wars  game. 

(defflavor  ship 

(x-position  y-position 
x-velocity  y-velocity  mass) 
()) 

It  states  that  all  instances  of  flavor  ship  will  have  five  instance  variables,  as  listed. 
(The  empty  list  following  the  instance  variables  is  related  to  a  feature  we'll  consider 
in  the  section  "Mixing  Flavors.")  Here  are  two  methods  for  the  ship  flavor,  to  han- 
dle the  messages    : speed  and    : direction. 

(def method  (ship  : speed)  () 

( sqrt  (+  (expt  x-velocity  2) 

(expt  y-velocity  2)))) 

(def method  (ship  : direction)  () 
(atan  y-velocity  x-velocity)) 

A  defmethod  looks  very  much  like  a  defun.  It  has  a  function-spec,  an  argument 
list,  and  a  body.  The  body  will  be  executed  in  an  environment  in  which  the  names 
of  ship's  instance  variables  will  refer  to  the  instance  variables  of  the  specific  ship 
object  which  received  the  message. 

We  might  also  wish  to  have  methods  which  allow  one  to  examine  the  values  of 
ship's  instance  variables.   Like: 

(defmethod  (ship  : x-position)  () 
x-position) 


Section  2.1  Basic  Usage  19 


Writing  one  of  these  methods  for  every  instance  variable  would  be  tedious.  For- 
tunately there  is  an  option  to  defflavor  that  automatically  generates  such  methods 
for  all  the  instance  variables.  There  is  also  an  option  which  causes  defflavor  to 
automatically  generate  methods  for  setting  the  values  of  all  the  instance  variables. 
Their  definitions  are  as  though  one  had  done: 

(def method  (ship  : set-x-position)  (new-position) 
(setq  x-position  new-position)) 

To  get  both  of  these  options,  our  updated  call  to  defflavor  would  look  like: 

(defflavor  ship 

(x-position  y-position 
x-velocity  y-velocity  mass) 
() 
: gettable-instance-variables 
: settable-instance-variables ) 

To  make  an  instance  of  flavor  ship,  we  use  the  make-instance  function:* 

(setq  my-ship  (make-instance  'ship)) 

This  will  return  an  object  whose  printed  representation  looks  like  #<SHIP 
25564553>.  (The  funny  number  will  be  the  virtual  memory  address,  in  octal,  of 
the  instance.) 

To  send  a  message  to  an  instance,  you  use  the  send  function.  (The  effect  of  send  is 
in  fact  identical  to  that  of  funcall,  but  when  funcalling  an  instance  send  is  preferred 
for  reasons  of  clarity.)    We  can  now  do  things  like: 

(send  my-ship  : set-x-velocity  1000) 

(send  my-ship  : set-y-velocity  500) 

(send  my-ship  : speed)        -         1118.0339 

In  addition  to  the  instance  variables,  another  very  important  variable  is  bound  dur- 
ing the  execution  of  a  method.  The  value  of  the  variable  self  will  be  the  instance 
object  itself.   It's  often  used  to  send  the  object  another  message: 

(def method  (ship  : check-speed)  () 


in  the  special  case  where  the  object  is  a  window,  you  should  instead  use  tv:make-window,  which  will 
perform  some  necessary  bookkeeping  operations  in  addition  to  calling  make-instance  for  you. 


20  WHAT'S  A  FLAVOR?  Chapter  2 


(when  (>  (send  self  : speed)  3.0e8) 

(f error  "travel  at  rates  greater  than  the  - 
speed  of  light  is  not  permitted" ) ) ) 


2.2  Initial  Values  for  Instance  Variables 

Instances  of  our  ship  flavor  start  out  with  all  their  instance  variables  unbound. 
Sending  a  newly  constructed  ship  the  :x-velocity  message,  for  instance,  would 
result  in  an  unbound-variable  error.  But  there  are  two  ways  to  arrange  for  initial 
values  to  be  assigned  to  an  instance  when  it  is  made.  If  you  have  used  the 
:  initable-instance-variables  option  to  defflavor,  then  you  may  specify 
the  initial  values  in  the  call  to  make-instance.   So  with  this  defflavor: 

(defflavor  ship 

(x-position  y-position 
x-velocity  y-velocity  mass) 
() 
: gettable-instance-variables 
: settable-instance-variables 
: initable-instance-variables ) 

you  could  use  this  call  to  make-instance: 

(make-instance  'ship  : x-position  30  : y-position  -150 
:mass  10) 

The  instance  variables  mentioned  in  the  call  will  have  the  specified  initial  values. 
Instance  variables  not  mentioned  will  be  unbound,  as  before.  Now  suppose  you 
want  all  instances  to  have  certain  initial  values  for  certain  instance  variables. 
Perhaps  you  want  the  x-velocity  and  y-velocity  of  all  new  ships  to  be  0.  You  could 
specify  so  in  every  call  to  make-instance.  But  there  is  an  easier  way.  You  can 
specify  in  the  defflavor  what  initial  value  you  wish  the  instance  variables  to  have. 
Here's  our  next  version  of  the  defflavor  for  ship: 

(defflavor  ship  (x-position 
y-position 
(x-velocity  0) 
(y-velocity  0) 
mass) 


() 
: gettable-instance-variables 


Section  2.2  Initial  Values  for  Instance  Variables  21 


: settable-instance-variables 
: initable-instance-variables ) 

Now  all  ships  will  start  out  with  x-  and  y-  velocities  of  0  —  unless  you  specify  oth- 
erwise in  the  make-instance.  An  initial  value  specified  in  make-instance  will  over- 
ride any  default  initial  values  given  in  the  defflavor. 

Here  is  a  slightly  more  complex  example,  taken  from  p.  427  of  the  flavor  documen- 
tation: 

(defvar  *def ault-x-velocity*  2.0) 
(defvar  *default-y-velocity*  3.0) 

(defflavor  ship  ( (x-position  0.0) 
( y-position  0.0) 

(x-velocity  *def ault-x-velocity* ) 
(y-velocity  *def ault-y-velocity* ) 
mass ) 
() 
: gettable-instance-variables 
: settable-instance-variables 
: initable-instance-variables ) 

(setq  another-ship 

(make-instance  "ship  :x-position  3.4)) 

The  values  of  the  new  ship's  instance  variables  will  be  3.4  for  x-position  (the 
make-instance  specification  overrides  the  default  of  0.0),  0.0  for  y-position  (the 
default),  2.0  for  x-velocity  and  3.0  for  y-velocity  (the  values  of  the  two  global  vari- 
ables), and  mass  will  be  unbound. 

It's  useful  to  know  that  describe,  a  function  which  tries  to  print  helpful  information 
about  its  argument,  no  matter  what  it  is,  lists  the  values  of  all  the  instance  vari- 
ables when  applied  to  an  instance: 

(describe   another-ship)      would  print 

#<SHIP  40113625>,  an  object  of  flavor  SHIP, 
has  instance  variable  values : 
X-POSITION:  3.4 

Y-POSITION:  0.0 

X-VELOCITY:  2.0 


22  WHAT'S  A  FLAVOR?  Chapter  2 


Y-VELOCITY:  3.0 

MASS :  unbound 


2.3  Mixing  Flavors 

The  real  power  of  the  flavor  system  lies  in  its  facility  for  producing  new  flavors  by 
combining  existing  ones.  Suppose  we  wished  to  define  an  "asteroid"  object.  It 
would  need  much  of  the  same  functionality  as  the  ship  flavor.  In  fact,  all  of  ship's 
instance  variables  and  methods  would  be  appropriate.  But  we  do  want  to  have  two 
distinct  kinds  of  object,  because  we  might  wish  to  add  more  functionality  to  ship 
and  asteroid  which  would  not  be  shared.  Ship,  for  instance,  could  use  an  instance 
variable  for  its  engine  power,  or  we  might  want  to  give  each  ship  a  name.  And  for 
each  asteroid  we  might  want  to  characterize  its  composition  (perhaps  part  of  the 
game  requires  replenishing  resources  by  mining  asteroids). 

One  way  to  handle  the  situation  would  be  to  duplicate  the  lisp  code  for  the  common 
functionality  in  both  flavors.  Such  duplication  would  clearly  be  wasteful,  and  the 
program  would  become  far  more  difficult  to  maintain  —  any  modifications  would 
have  to  be  repeated  in  both  places.  A  better  approach  would  be  to  isolate  the  com- 
mon functionality  and  make  it  a  flavor  in  itself.  We  can  call  it  "moving-object." 
Now  the  ship  and  asteroid  flavors  can  be  built  on  moving-object.  We  just  need  to 
specify  the  added  functionality  each  has  beyond  that  provided  by  moving-object. 
The  defflavor  for  moving-object  can  be  exactly  like  our  existing  defflavor  for  ship. 
The  new  ship  defflavor  will  have  moving-object  specified  in  its  list  of  component 
flavors,  which  up  until  now  has  been  an  empty  list. 

(defflavor  ship  (engine-power  name) 
(moving-object) 
: gettable-instance-variables 
: initable-instance-variables ) 

And  asteroid: 

(defflavor  asteroid  (percent-iron) 
(moving-object) 
: gettable-instance-variables 
: initable-instance-variables ) 

Ship  and  asteroid  both  inherit  all  of  moving-object's  instance  variables  (including 
their  default  values)  and  all  of  its  methods.  They  are  each  specializations  of  the 
abstract  type  moving-object.    And  the  specialization  could  continue.     We  could 


Section  2.3  Mixing  Flavors  23 


define  a  "ship-with-passengers"  flavor,  built  on  ship,  with  an  added  instance  vari- 
able passengers,  and  added  methods  for  :add-passenger  and  :  remove- 
passenger. 

A  flavor  is  not  limited  to  having  only  one  component  flavor  —  it  may  have  any 
number.  So  the  set  of  components  for  a  given  flavor  is  actually  a  tree,  consisting  of 
all  the  flavor's  direct  components,  and  all  of  their  direct  components,  and  so  on. 
Figure  1  shows  the  tree  for  the  flavor  tv:lisp-listener.  (All  are  in  the  tv  package, 
unless  otherwise  noted.)  As  you  can  see,  it  can  get  quite  elaborate.  tv:lisp-listener 
has  26  component  flavors  in  all.  Of  the  287  handlers  I  mentioned  earlier  that 
tv:lisp-listener  has,  only  one  of  them  is  locally  defined  in  tv:lisp-listener.  The  rest 
are  all  inherited,  about  150  from  tvrsheet  alone,  and  another  50  or  so  from 
tv:stream-mixin. 


2.4  Combined  Methods 

Saying  simply  that  a  flavor  inherits  all  the  methods  of  its  components  sweeps  an 
important  issue  under  the  rug.  What  happens  if  more  than  one  of  its  components 
define  methods  for  the  same  message?  Which  gets  used?  It  depends  on  the  order- 
ing of  the  component  flavors.  As  it  says  on  p.  432  of  the  documentation,  "The  tree 
of  flavors  is  turned  into  an  ordered  list  by  performing  a  top-down,  depth-first  walk 
of  the  tree,  including  nonterminal  nodes  before  the  subtrees  they  head,  and  elim- 
inating duplicates."  So  the  for  tv:lisp-listener,  the  ordered  list  starts  with:  lisp- 
listener,  listener-mixin,  listener-mixin-internal,  process-mixin,  window... 

If  more  than  one  component  flavor  defines  a  method  for  a  given  message,  with  the 
kind  of  methods  we  have  seen  so  far,  the  one  which  appears  first  on  the  list  is  taken 
as  the  combined  flavor's  method  for  that  message.  In  particular,  this  means  that 
any  methods  (again,  of  the  type  we  have  seen  so  far)  defined  locally  in  the  new 
flavor  will  supersede  all  methods  (for  the  same  message)  defined  in  any  of  the  com- 
ponent flavors,  since  the  new  flavor  is  first  on  the  ordered  list.  For  example,  the 
flavors  tv.lisp-listener  and  tv:essential-window  both  define  methods  for  the  message 
:  lisp-listener-p.  The  one  in  tv:essential-window  always  returns  nil.  The 
one  in  tv:lisp-listener  always  returns  t.  So  a  window  without  tv:lisp-listener  mixed 
in  will  answer  the  :  lisp-listener-p  message  with  nil.  But  a  lisp-listener 
will  answer   t,  because  its  local  method  overrides  tv:essential-window's. 

[There  is  an  exception  to  the  top-down  depth-first  rule.  If  you're 
already  confused,  skip  these  two  paragraphs  for  now  and  come 
back  later.  If  not,  it's  time  to  learn  about  the  :  included- 
flavors  option  to  defflavor.    Suppose  you're  defining  a  flavor 


24 


WHAT'S  A  FLAVOR? 


Chapter  2 


LISP-LISTENER 


LISTENER-MIXIN 


LISTENER- 

MIXIN- 
INTERNAL 
/ 
PROCESS  STREAM 


BORDERS 
MIXIN 


MIXIN- 


MIXIN 


WINDOW 


SELECT- 

MIXIN 


MINIMUM- 
WINDOW 


LABEL- 
MIXIN 


GRAPHICS- 
MIXIN 


ESSENTIAL- 
EXPOSE 


ESSENTIAL- 
SET-EDGES 


ESSENTIAL- 
WINDOW 


ESSENTIAL- 
LABEL- 
MIXIN 


ESSENTIAL- 
ACTIVATE 


ESSENTIAL- 
MOUSE 


MARGIN-HACKER-MIXIN 
Sh  INTERACTIVE -STREAM 


ShLINE-OUTPUT 
STREAM-MIXIN 


ST.BIDIRECTION- 
STREAM 


ShCHARACTER 
STREAM 


SHEET 


ShOUTPUT- 
STREAM 


ShSTREAM 


SL-INPUT-STREAM 


Figure  1.  Flavor  tree  for  lisp-listener 


Section  2.4  Combined  Methods  25 


(call  it  my-flavor)  which  is  intended  to  be  used  as  a  component  for 
other  flavors  (call  one  of  them  user-flavor).  And  suppose  that  for 
the  methods  defined  in  my-flavor  to  work  properly,  it's  necessary 
that  some  other  flavor  (call  it  needed-flavor)  also  be  mixed  into  the 
user-flavor.  And  suppose  further  that  needed-flavor  is  a  rather 
basic  flavor,  and  so  should  appear  towards  the  end  of  user-flavor's 
ordered  list.  You  could  guarantee  that  needed-flavor  always  be 
present  whenever  my-flavor  is  present  by  making  it  a  component  of 
my-flavor.  But  then  it  would  appear  just  behind  my-flavor  in 
user-flavor's  ordered  list  of  components.  (Possibly  closer  to  the 
front  if  some  other  component  flavor  uses  it,  but  certainly  no 
further  back.)  And  some  of  needed-flavor's  methods  might  over- 
ride methods  of  other  flavors  which  were  really  intended  to  over- 
ride needed-flavor's  methods,  expecting  to  find  needed-flavor  near 
the  end  of  the  list.  The  solution  here  is  the  rincluded- 
flavors  option.  My-flavor  lists  needed-flavor  as  an  included 
flavor.  The  effect  is  that  when  user-flavor  uses  my-flavor,  needed- 
flavor  will  appear  in  the  ordered  list  immediately  after  my-flavor 
only  if  no  other  flavors  in  user-flavor  have  needed-flavor  as  a  com- 
ponent. If  some  other  flavor  does  —  and  the  expected  case  is  that 
somebody  near  the  end  of  the  list  will  —  then  needed-flavor  will 
appear  there,  as  though  my-flavor  never  mentioned  it. 

An  example:  look  back  at  the  lisp-listener  tree,  and  note  the  posi- 
tion of  process-mixin.  It  will  be  the  fourth  flavor  in  lisp-listener's 
ordered  list.  The  defflavor  for  process-mixin  specifies  that 
essential-window  is  an  "included-flavor,"  because  for  process-mixin 
to  work  properly,  any  flavor  which  uses  it  must  also  use  essential- 
window.  But  if  process-mixin  specified  essential- window  as  a  nor- 
mal component,  essential-window  would  be  brought  all  the  way 
from  its  current  position  near  the  end  of  the  list  to  fifth  position, 
just  behind  process-mixin.  Worse  yet,  sheet  would  be  pulled  from 
last  to  sixth,  because  it  is  a  component  (normal)  of  essential- 
window.  But  many  of  sheet's  methods  are  supposed  to  be  overrid- 
den by  the  other  flavors,  e.g.,  select-mixin.  If  sheet  were  pulled  in 
front  of  select-mixin,  the  lisp-listener  would  never  see  many  of  the 
select-mixin  methods,  and  it  wouldn't  behave  properly  at  all. J 

As  I've  hinted,  there  are  more  kinds  of  methods  than  we  have  so  far  seen.  All  our 
methods  have  been  what  are  called  "primary"  methods,  and  by  default,  when  there 
is  more  than  one  primary  method  for  the  same  message  in  the  ordered  list  of  com- 
ponent flavors,  the  one  which  appears  first  overrides  all  others.    But  sometimes  you 


26  WHAT'S  A  FLAVOR?  Chapter  2 


don't  want  to  completely  override  the  inherited  primary  method;  sometimes  you 
would  like  to  specify  something  to  be  done  in  addition  to  the  action  of  the  inherited 
method  rather  than  instead  of.  Then  you  would  define  a  : before  or  an  rafter 
method,  often  called  before  and  after  daemons. 

Here's  how  it  works.   Suppose  I  did  the  following  defmethod: 

(def method  (asteroid  rafter  : speed)  () 
(do-something-or-other ) ) 

Asteroid  already  has  a  primary  :  speed  method,  inherited  from  moving-object. 
Once  this  new  rafter  :  speed  method  is  defined,  asteroid  will  have  a  "com- 
bined method"  for  r  speed,  consisting  of  a  call  to  the  moving-object  primary 
method  followed  by  a  call  to  the  asteroid  r  after  method.  Any  number  of  flavors 
in  the  ordered  list  of  components  may  provide  daemons.  They  will  all  be  included 
in  the  resulting  combined  method.  To  quote  from  the  documentation  again, 
"Before-daemons  are  called  in  the  order  that  flavors  are  combined,  while  after- 
daemons  are  called  in  the  reverse  order.  In  other  words,  if  you  build  bar  on  top  of 
foo,  then  bar's  before-daemons  will  run  before  any  of  those  in  foo,  and  bar's  after- 
daemons  will  run  after  any  of  those  in  foo."  The  primary  method  which  appears 
first  in  the  list  will  be  called  after  all  the  before  daemons  (even  if  some  of  the 
before  daemons  appear  later  in  the  list  than  the  primary  method)  and  before  all  the 
after  daemons. 

The  value  returned  by  a  combined  method  is  exactly  the  value  returned  by  the  pri- 
mary method  —  before  and  after  daemons  are  executed  only  for  side  effect,  i.e., 
their  return  values  are  ignored.  It  is  allowable  to  have  before  and  after  daemons 
for  a  message  which  has  no  primary  method;  in  such  a  case  the  combined  method 
will  return  nil. 

Before  and  after  daemons  provide  a  lot  of  flexibility  (perhaps  more  than  you'd  like 
to  have  just  yet),  but  sometimes  not  enough.  Fairly  frequently  a  situation  demands 
altering  the  context  in  which  a  primary  method  runs.  A  typical  case  would  be 
binding  a  special  variable  to  some  value  around  the  execution  of  the  primary 
method,  or  putting  the  primary  method  into  an  unwind-protect  or  inside  a  catch.* 
Or  deciding  in  some  cases  to  skip  the  primary  method  altogether.  Before  and  after 
daemons  are  unable  to  do  any  of  these.  The  kind  of  method  which  can  is  called  a 
whopper. 

Whoppers  are  best  explained  by  example.    Here  are  three  which  handle  the  cases  I 


*      If  unwind-protect  or  catch  are  unfamiliar,  you  might  want  to  look  them  up  in  volume  2. 


Section  2.4  Combined  Methods  27 


just  listed.  To  understand  them  you'll  need  to  know  that  continues  hopper  is  a 
system-provided  function  which  calls  the  regular  (non-whopper)  methods  for  this 
message. 

(def whopper  (some-flavor  : some-message )  (argl  arg2 ) 
(let  ((some-special-variable  temporary-value)) 
(continue-whopper  argl  arg2 ) ) ) 

(def whopper  (some-flavor  : some-message )  (argl  arg2 ) 
( unwind-protect 
(progn  (setup) 

(continue-whopper  argl  arg2 ) ) 
(cleanup) ) ) 

(def whopper  (some-flavor  : some-message )  (argl  arg2 ) 
(unless  (some-special-test  argl) 
(continue-whopper  argl  arg2 ) ) ) 

Unlike  before  and  after  daemons,  whoppers  have  control  over  the  value  returned  by 
the  combined  method.  They  most  commonly  just  pass  up  the  value  returned  by 
continue-whopper  (which  will  be  whatever  the  primary  method  returns,  as  before), 
but  they  needn't.    I  could,  for  instance,  do  this: 

(def whopper  (doubling-mixin  : calculate)  (argl  arg2) 
(*  2  (continue-whopper  argl  arg2))) 

And  since  continue-whopper  is  just  a  function  like  any  other,  there's  no  reason  you 
couldn't  do  something  like  this: 

(def whopper  (doubling-mixin-of-another-sort  : some-message) 
(argl  arg2 ) 
(continue-whopper  argl  arg2 ) 
(continue-whopper  argl  arg2 ) ) 

(def whopper  (yet-another-doubling-mixin  : some-message) 
(argl  arg2 ) 
(continue-whopper  argl  (continue-whopper  argl  arg2 ) ) ) 

One  point  about  ordering  needs  to  be  clarified.  A  whopper  surrounds  not  just  the 
primary  method,  but  all  the  before  and  after  daemons,  too.  So  suppose  flavor  "out" 
is  built  on  top  of  "in,"  and  both  out  and  in  have  a  whopper,  a  before  daemon,  an 
after  daemon,  and  a  primary  method  for  message     :  mumble.    Out's  combined 


28  WHAT'S  A  FLAVOR?  Chapter  2 


method  for    :  mumble  would  look  like  Figure  2. 


out-before 
in-before 
out-whopper    in-whopper   out-primary 

in-after 
out-after 


Figure  2.  Structure  of  combined  method 

There  is  another  kind  of  construct  called  a  wrapper.  This  was  the  predecessor  of  the 
whopper,  but  now  that  the  whopper  exists,  which  is  easier  to  use,  there  is  seldom 
any  need  to  use  wrappers. 


2.5  Other  Ways  of  Combining  Methods 

All  that  I  said  in  the  previous  section  applied  only  to  the  default  style  of  combining 
methods,  called  the  :  daemon  type.  There  are  actually  about  a  dozen  different 
types  of  method  combination.  Moreover,  users  can  define  additional  types  (with 
some  effort).  Before  despairing,  though,  note  that  at  least  90%  of  the  time  the 
:  daemon  type  of  method  combination  is  used.  All  of  the  built-in  types  are  dis- 
cussed in  chapter  53  of  Symbolics  volume  2,  "Method  Combination."  I  will 
describe  one  of  them,  the  :  or  type,  both  because  it  is  a  relatively  simple  example 
of  what  can  be  done,  and  because  I've  actually  seen  it  used. 

First,  in  order  to  specify  that  you  wish  to  use  a  type  of  method  combination  other 
than  daemon,  you  use  the    : method-combination  option  to  defflavor.  Here  is  a 


Section  2.5  Other  Ways  of  Combining  Methods  29 


defflavor  pulled  from  the  source  code  for  the  window  system: 

(DEFFLAVOR  ESSENTIAL-MOUSE  ()  () 

( : INCLUDED-FLAVORS  ESSENTIAL-WINDOW) 

(: METHOD-COMBINATION  ( :OR  : BASE-FLAVOR-LAST  : MOUSE-CLICK) ) ) 


essential-mouse  is  one  of  the  flavors  that  appears  in  the  lisp-listener  tree  given 
above.  It's  the  mixin  that  enables  a  window  to  interact  properly  with  the  mouse. 
As  you  can  see,  this  flavor  has  no  instance  variables  and  no  component  flavors.  It 
has  essential-window  as  an  :  included-f  lavor,  though  that  has  no  bearing  on 
the  immediate  issue  of  non-standard  method  combination.  The  :  method- 
combination  option  is  what  concerns  us.  It  says  that  the  : mouse-click 
methods  for  all  flavors  built  on  this  flavor  should  use  :or  style  combination,  and 
that  the  order  of  combination  should  be  base  flavor  (essential-mouse)  last. 

So  what's  :or  combination,  and  what  does  base-flavor-last  mean?  In  :or  combi- 
nation, all  the  methods  appearing  in  the  ordered  list  of  component  flavors  are  col- 
lected, and  each  is  called  in  turn.  If  a  particular  method  returns  a  non-nil  value, 
the  remaining  methods  are  skipped.  Otherwise  (the  method  returned  nil),  the 
next  one  is  called.  We  just  step  through  all  the  methods,  stopping  as  soon  as  one 
returns  a  non-nil  value.  Base-flavor-last  means  that  the  essential-mouse  method  for 
: mouse-click  will  be  the  last  one  to  be  tried,  i.e.,  the  methods  will  be  collected 
and  tried  in  the  exact  same  order  as  their  flavors  appear  in  the  ordered  list  of  com- 
ponents.  The  opposite  ordering  may  be  specified  with    :base-f  lavor-f  irst. 

Suppose  I  define  a  flavor  built  (directly  or  indirectly)  on  essential-mouse,  and  give 
my  flavor  a  : mouse-click  method.  Then  whenever  the  : mouse-click  mes- 
sage is  sent  to  an  instance  of  my  flavor,  my  : mouse-click  method  will  be  called. 
If  my  method  returns  anything  other  than  nil,  no  other  : mouse-click 
methods  will  be  called.  If  my  method  returns  nil,  then  any  .-mouse -click 
methods  defined  by  flavors  which  are  components  of  my  flavor  will  get  a  chance.  If 
the  only  other  : mouse-click  method  is  essential-mouse's,  or  if  all  the  others 
return  nil,  then  the  essential-mouse  method  for    : mouse-click  will  be  called. 

The  : mouse-click  message  is  sent  to  the  window  under  the  mouse  blinker 
whenever  you  press  one  of  the  mouse  buttons.  (The  mouse  process  takes  care  of 
sending  the  message  —  you  don't  need  to  worry  about  it.)  If  you  want  to  do  some- 
thing special  when  the  buttons  are  pressed,  you  simply  need  to  define  an  appropri- 
ate : mouse-click  method.  Now  there  are  six  different  kinds  of  button  presses 
(three  different  buttons,  and  single  or  double  clicks  on  each  button).  Maybe  you 
have  something  you  want  to  do  if  there  is  a  single  click  on  the  left  button,  but  not 


30  WHAT'S  A  FLAVOR?  Chapter  2 


if  there  is  a  double  click  on  the  middle  button.  One  of  the  arguments  to  the 
method  will  tell  which  kind  of  button  press  there  was,  so  your  method  should  test 
the  argument,  and  if  it's  the  kind  of  button  press  you  want  to  handle  (single  left), 
do  whatever  you  had  in  mind,  and  return  something  non-nil,  so  that  the  other 
: mouse-click  methods  won't  be  called  and  possibly  do  something  else  with  the 
single  left  click,  interfering  with  your  action.  If  it's  some  button  press  that  you 
don't  care  about  (double  middle),  return  nil  so  that  the  other  methods  will  have  a 
chance  to  handle  it. 

Here's  essential-mouse's  method  for  : mouse-click,  which  is  called  if  no  one  else 
handles  the  button  press: 

(DEFMETHOD  (ESSENTIAL-MOUSE  : MOUSE-CLICK)  (BUTTONS  X  Y) 
(COND  ((AND  (=  BUTTONS  #\MOUSE-L-1) 

(NEQ  SELF  SELECTED-WINDOW) 
(GET-HANDLER-FOR  SELF  ': SELECT)) 
(MOUSE-SELECT  SELF) 
(SEND-IF-HANDLES  SELF  : FORCE-KBD- INPUT 

x ( : MOUSE- BUTTON  , BUTTONS  , SELF  ,X  ,Y) 
T)) 
( (OPERATION-HANDLED-P  SELF  : FORCE-KBD- INPUT) 
(SEND  SELF  : FORCE-KBD-INPUT 

*( : MOUSE-BUTTON  , BUTTONS  , SELF  ,X  ,Y) 
T)) 
((=  BUTTONS  #\MOUSE-R-1) 

(MOUSE-CALL- SYSTEM-MENU) ) 
(T 
(BEEP) ) ) 
T) 


You  don't  need  to  understand  all  the  details  to  write  your  own  : mouse-click 
methods.  All  you  need  to  understand  is  the  general  format  of  testing  the  "buttons" 
argument  and  choosing  some  action  accordingly. 


2.6  Vanilla-flavor 

shvanilla-flavor  is  the  generic  flavor  on  which  all  other  flavors  are  built.  Even  if 
your  defflavor  specifies  no  components,  your  flavor  will  still  have  vanilla-flavor 
mixed  in  because  the  flavor  system  does  it  automatically  (unless  you  explicitly 
instruct  otherwise  with  the     :no-vanilla-f lavor  option  to  defflavor).     But 


Section  2.6  Vanilla-flavor  31 


don't  complain,  because  vanilla-flavor  is  very  handy.  It  provides  several  extremely 
important  methods.  The  : print-self  method  is  called  whenever  an  instance  is 
to  be  printed.  (The  representation  of  the  first  ship  instance  we  made,  #<SHIP 
25564553>,  was  actually  printed  on  my  monitor  by  ship's  : print-self 
method,  inherited  from  vanilla-flavor.)  The  : describe  method  is  used  by  the 
describe  function.  (The  example  shown  earlier,  where  the  describe  function  listed 
all  of  a  particular  ship's  instance  variables,  was  printed  by  ship's  :  describe 
method,  also  inherited  from  vanilla-flavor.)  The  :which-operations  method 
returns  a  list  of  all  the  messages  handled  by  the  object.  The  :get-handler- 
f  or  method  takes  one  argument,  the  name  of  a  message,  and  returns  the  function 
object  which  is  the  instance's  handler  for  that  message. 

See  chapter  52  in  the  flavor  documentation  for  the  remaining  vanilla-flavor 
methods. 


2.7  Fun  and  Games 

And  from  The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  ah 

FLAVOR  noun. 

1.  Variety,  type,  kind.  "Emacs  commands  come  in  two  flavors:  single-character 
and  named."  "These  lights  come  in  two  flavors:  big  red  ones  and  small  green 
ones."   See  VANILLA. 

2.  The  attribute  that  causes  something  to  be  FLAVORFUL.  Usually  used  in  the 
phrase  "yields  additional  flavor."  Example:  "This  feature  yields  additional 
flavor  by  allowing  one  to  print  text  either  right-side-up  or  upside  down." 

VANILLA  adjective. 

Standard,  usual,  of  ordinary  FLAVOR.  "It's  just  a  vanilla  terminal;  it 
doesn't  have  any  interesting  FEATURES."  When  used  of  food,  this  term 
very  often  does  not  mean  that  the  food  is  flavored  with  vanilla  extract!  For 
example,  "vanilla-flavored  wonton  soup"  (or  simply  "vanilla  wonton  soup") 
means  ordinary  wonton  soup,  as  opposed  to  hot-and-sour  wonton  soup. 

This  word  differs  from  CANONICAL  in  that  the  latter  means  "the  thing  you 
always  use  (or  the  way  you  always  do  it)  unless  you  have  some  strong  reason 
to  do  otherwise,"  whereas  "vanilla"  simply  means  "ordinary."  For  example, 
when  MIT  hackers  go  to  Colleen's  Chinese  Cuisine,  hot-and-sour  wonton 
soup  is  the  canonical  wonton  soup  to  get  (because  that  is  what  most  of  them 
usually  order)  even  though  it  isn't  the  vanilla  wonton  soup. 


32  WHAT'S  A  FLAVOR?  Chapter  2 


2.8  Problem  Set  #2 

Questions 

Part  I 

1.  Define  a  function  of  four  arguments  that  draws  a  square.  The  args  are  the 
window,  the  x  and  y  coords  of  the  square's  center,  and  the  size  (length  of 
each  side). 

2.  Define  a  flavor  of  window  which  handles  a  :  draw- square  message  by  call- 
ing your  draw-square  function.  Then  create  a  window  of  that  flavor,  being 
sure  to  keep  a  pointer  to  it,  and  verify  that  the  : draw-square  message 
works. 

3.  Make  the  size  argument  to  the  method  optional,  defaulting  to  the  value  of  a 
global  variable  *square-size*.   Make  the  default  size  100  pixels. 

4.  Arrange  it  so  that  clicking  left  on  the  mouse  while  over  your  window  draws  a 
square  centered  on  the  mouse  position,  using  the  default  size. 

5.  A.   Try  these  out  —  they  temporarily  bind  the  default  size  to  50  instead  of 

100,  and  then  draw  a  square  using  the  default  size. 


(let    ( (*square-size*   50)) 

(send  w    : draw-square    150    150)) 


(let    ( (*square-size*    50)) 

( process-sleep   300  )  )  click  left  over  my-window  during  the  sleep 

Why  doesn't  the  second  work?    Why  isn't  the  binding  of  *square-size* 
to  50  being  seen? 

B.  There  is  special  form  called  let-globally  which  will  get  around  this 
problem.  Look  it  up  in  the  manual  and  use  it  with  a  process-sleep  so 
that  clicking  left  over  the  window  will  make  a  square  whose  size  is  con- 
trolled by  the  let-globally. 

Making  the  default  size  an  instance  variable  will  get  around  the  problem 
addressed  in  (5),  and  has  several  other  advantages.  We  no  longer  clutter 
things  up  with  an  extra  global  variable.  More  important,  with  the  default 
size  an  instance  variable,  it's  possible  for  each  instance  of  my-window  to 
simultaneously  have  a  different  value  for  default-square-size. 

Redefine  your  flavor  of  window  (and  make  a  new  instance)  so  the  following 
works: 


Section  2.8  Problem  Set  #2  33 


(let  ((old-size  (send  w  :def ault-square-size) ) ) 
(send  w  : set-default-square-size  50) 
(process-sleep  300) 
(send  w  : set-default-square-size  old-size)) 

7.  What  would  happen  if,  during  the  process-sleep  in  the  let  in  problem  (6),  I 
typed  c-Abort?  The  reset  of  default-square-size  back  to  its  previ- 
ous value  would  never  happen.  The  let,  which  is  intended  to  be  without 
side-effect,  would  have  permanently  changed  the  value  of  the  instance  vari- 
able. 

Add  something  to  the  let  in  problem  (6)  so  that  it  will  be  guaranteed  to  reset 
default-square-size  to  its  previous  value. 

8.  Without  duplicating  any  code,  define  a  new  flavor  of  window,  doubling- 
window,  which  behaves  just  like  the  window  you've  already  defined,  except 
that  the  squares  it  draws  are  twice  as  big  as  you  ask  for.  That  is,  if  you  click 
left  the  square  will  be  twice  the  size  specified  by  the  window's  default- 
square-size  instance  variable,  and  if  you  explicitly  send  the  :  draw- 
square  message  the  square  will  be  twice  the  size  specified  by  the  third  argu- 
ment to  the  message. 

Part  II 

Not  too  long  ago,  I  had  to  track  down  some  bugs  in  the  speech  editor  I  was  work- 
ing on,  related  to  the  ordering  of  the  components  of  one  of  my  flavors.  I  had 
switched  the  order  of  two  components  to  fix  one  bug,  and  apparently  introduced 
some  new  ones.  At  least,  the  program  was  misbehaving  in  a  way  it  previously 
hadn't,  and  the  only  relevant  change  I'd  made  was  the  component  reordering.  It 
was  a  sort  of  misbehavior  that  would  have  been  difficult  to  debug  by  interrupting 
the  program  while  it  was  doing  the  wrong  thing,  examining  the  state  of  the  world, 
and  working  back  to  see  which  message-handler  was  responsible  for  the  new 
behavior.  So  I  instead  decided  to  find  out  what  messages  would  be  handled 
differently  with  the  new  component  ordering,  and  work  forward  to  see  which  of 
those  changed  handlers  could  be  causing  the  odd  behavior. 

The  Flavor  Examiner  (Select-X)  has  a  facility  for  listing  all  the  message-handlers 
of  a  given  flavor,  together  with  the  name  of  the  flavor  the  handler  was  inherited 
from.  So  all  I  had  to  do  was  list  all  the  handlers  for  my  two  flavors,  and  compare 
them.  If  only  one  of  the  two  handled  a  particular  message,  it  wouldn't  matter  in 
which  order  the  flavors  were  mixed  in,  since  I  would  get  the  same  handler  either 
way.  And  if  they  both  handled  a  message,  but  handled  it  with  the  same  inherited 
method  from  a  common  component,  the  order  of  combination  still  wouldn't  matter. 
Any  messages,  however,  which  were  handled  by  both  flavors  but  with  different 


34  WHAT'S  A  FLAVOR?  Chapter  2 


methods,  would  be  likely  suspects.  Which  handler  my  combined  flavor  had  would 
indeed  depend  on  the  order  of  combination. 

It  would  have  been  a  simple  task,  except  that  the  two  flavors  involved  each  had 
between  190  and  200  handlers.  Both  included  the  flavor  tv:  window,  which  has  194 
handlers.  Nearly  all  of  the  handlers  I  had  to  wade  through  were  internal  to 
tvrwindow  (mainly  from  the  flavors  tvrsheet  and  tv:stream-mixin) ,  and  shared  by  my 
two  flavors.  There  were  only  a  handful  of  suspects,  and  once  I  found  them  it  did 
not  take  too  long  to  realize  that  my  mistake  had  been  in  using  tv:window-pane 
where  I  should  have  used  tv:pane-mixin.  The  bugs  went  away.  But  it  was  a  far 
more  painful  experience  than  it  would  have  been  if  we  had  a  few  simple  utilities  for 
filtering  the  lists  of  handlers.  This  portion  of  the  problem  set  asks  you  to  write  a 
few  such  facilities. 

1 .  Write  a  function  of  two  arguments,  to  be  called  on  two  instantiated  objects  of 
different  flavors.  It  should  return  a  list  with  four  sublists:  a  list  of  handlers 
in  flavor- 1  and  not  in  flavor-2,  a  list  of  handlers  in  flavor-2  and  not  in  flavor- 
1,  a  list  of  handlers  in  both  flavors,  and  a  list  of  pairs  of  corresponding 
handlers,  for  messages  handled  by  both  flavors  but  with  different  handlers. 

2.  That's  already  enough  to  be  useful,  but  often  a  flavor  is  not  instantiated,  and 
sometimes  may  not  even  be  instantiable  without  further  mixins.  The  function 
you've  defined  won't  work  on  such  flavors.  Write  a  similar  function  which 
will  take  as  arguments  the  names  of  two  flavors. 

3.  The  answer  to  (1),  and  depending  on  how  you  did  it,  quite  possibly  the 
answer  to  (2),  are  subject  to  a  bug  of  sorts.  They  may  decide  under  certain 
conditions  that  two  handlers  are  different,  when  for  all  practical  purposes 
they  are  not.   Consider  the  following:* 


FOO  (foo) 

1.  interjection.   Term  of  disgust.   For  greater  emphasis,  one  says  MOBY  FOO  (see  MOBY). 

2.  noun.  The  first  metasyntactic  variable.  When  you  have  to  invent  an  arbitrary  temporary 
name  for  something  for  the  sake  of  exposition,  FOO  is  usually  used.  If  you  need  a  second  one, 
BAR  or  BAZ  is  usually  used;  there  is  a  slight  preference  at  MIT  for  bar  and  at  Stanford  for 
baz.  (It  was  probably  at  Stanford  that  bar  was  corrupted  to  baz.  Clearly,  bar  was  the  origi- 
nal, for  the  concatenation  FOOBAR  is  widely  used  also,  and  this  in  turn  can  be  traced  to  the 
obscene  acronym  "FUBAR"  that  arose  in  the  armed  forces  during  World  War  II.) 

Words  such  as  "foo"  are  called  "metasyntactic  variables"  because,  just  as  a  mathematical 
variable  stands  for  some  number,  so  "foo"  always  stands  for  the  real  name  of  the  thing  under 
discussion.  A  hacker  avoids  using  "foo"  as  the  real  name  of  anything.  Indeed,  a  standard 
convention  is  that  any  file  with  "foo"  in  its  name  is  temporary  and  can  be  deleted  on  sight. 


BAR 


The  second  metasyntactic  variable,  after  FOO.    If  a  hacker  needs  to  invent  exactly  two  names 


Section  2.8  Problem  Set  #2  35 


(def flavor  foo  ( )  ( ) ) 
(def flavor  bar  ( )  ( ) ) 

(def method  (foo  : silly-message )  ()  nil) 

(def method  (bar  : before  : silly-message)  ()  nil) 

(def flavor  flav-1  ( ) 

(foo  bar) ) 
(def flavor  flav-2  ( ) 

( foo  bar ) ) 

Flav-1  and  flav-2  each  have  a  combined  method  for  the  message  :  silly- 
message,  and  they  use  the  same  components  for  their  respective  combined 
methods.  I  would  like  these  two  combined  methods  to  be  considered  the 
same,  and  fall  into  the  third  of  our  four  sublists.  But  your  functions  may  be 
putting  such  pairs  of  methods  into  the  fourth  sublist.  If  so,  modify  one  or 
both  of  your  answers  to  (1)  and  (2)  to  re-classify  these  methods  accordingly. 

Of  all  your  answers  to  questions  (l)-(3),  select  the  one  that  seems  to  be  the 
most  useful,  and  merge  it  into  the  Flavor  Examiner. 


for  things,  he  almost  always  picks  the  names  "foo"  and  "bar." 
(The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  al) 


36  WHAT'S  A  FLAVOR?  Chapter  2 


Hints 

Part  I 

1.  Your  function  should  either  send  the  window  the  : draw- line  message  four 
times,  or  the  : draw- lines  message  once.  You  can  find  out  about  the 
arguments  to  the  : draw-line  and  : draw-lines  messages  by  looking 
them  up  in  the  index  to  volume  7. 

2.  Your  flavor  of  window  should  be  built  on  tv.window.  The  :  draw- square 
method  will  need  to  use  the   self  variable. 

Using  the  window  brings  up  a  somewhat  subtle  issue.  At  times  you'll  need 
the  lisp  listener  exposed  so  you  can  type  commands.  And  at  times  you'll  need 
your  new  window  exposed  so  it  can  display  the  squares  being  drawn.  You 
could,  then,  alternate  between  the  two  windows,  but  that  becomes  awkward. 
Far  better  is  to  position  and  shape  the  two  windows  such  that  they  can  both 
be  exposed  simultaneously.  One  procedure  would  be  to  first  narrow  the  lisp 
listener  down  to  the  left  half  of  the  screen  (choose  Edit  Screen  from  the  sys- 
tem menu,  then  Move  Single),  then  make  your  window  with  the  following 
form,  choosing  an  area  with  the  mouse  that  doesn't  overlap  the  narrowed  lisp 
listener: 

(setq  w  (tv: make -window  'my-window  :edges-from  : mouse 

:expose-p  t ) ) 

Now  you're  ready  to  try  drawing  squares,  with  (send  w  : draw-square 
...    ). 

3.  The  global  variable  should  be  defined  with  defvar  or  def const,  and  initialized 
to  100  in  the  call  to  defvar/const.  The  redefined  method  should  include  in  its 
arglist  "^optional    (size   *square-size*  )". 

4.  The  window  needs  a  : mouse-click  method.  Recall  that  :mouse-click 
methods  use  :  or  combination,  so  your  method  should  return  t  if  it  handles 
the  click,  and  nil  otherwise. 

5.  A.   Think  about  processes. 

B.   let-globally  looks  just  like  a  let. 

6.  The  flavor  will  have  an  instance  variable  named  default-square-size, 
and  you'll  need  to  use  the  rsettable-instance-variables  option. 
The  new    :  draw-  square  method  will  have  to  access  the  instance  variable. 

7.  Use  unwind -protect 


Section  2.8  Problem  Set  #2  37 


8.  Your  new  flavor  should  be  built  on  the  old  one,  and  should  have  a  whopper 
for    :  draw- square. 

Part  II 

1.  You  can  get  a  list  of  all  the  messages  an  object  handles  with  :which- 
operations.  And  given  a  specific  message,  you  can  get  the  handler  for  it 
with    :get-handler-for. 

2.  The  Flavor  Examiner  finds  the  methods  from  the  flavor  name,  without  having 
an  instantiated  object.  Find  out  how.  As  a  simpler  and  nearly  as  useful 
alternative,  note  that  the  editor  command  M-x  List  Combined  Methods 
(among  others)  can  do  the  same  thing  as  long  as  the  flavor  has  been  instan- 
tiated at  least  once,  and  track  down  what  it  does.  (Try  meta-.  on  com-list- 
combined-methods.)  This  won't  help  for  uninstantiated  flavors,  but  does 
remove  the  need  to  have  a  pointer  to  an  actual  instance  in  cases  where  the 
flavor  has  been  instantiated. 

3.  If  you're  modifying  your  answer  to  (1),  you're  probably  dealing  with  com- 
piled function  objects.  Notice  that  the  describe  function,  when  applied  to  the 
compiled  function  object  for  a  combined  method,  prints  the  necessary  infor- 
mation under  the  title  extra  info,  after  :f definition-location- 
hints.    Find  out  how. 

If  you're  modifying  your  answer  to  (2)  you  probably  already  have  a  data 
structure  containing  the  necessary  information,  and  you  just  need  to  make 
use  of  that  information  to  re-classify  the  handlers. 

4.  The  source  code  for  the  Flavor  Examiner  is  in  the  file  "sys:  window;  flavex." 


38 


WHAT'S  A  FLAVOR? 


Chapter  2 


Solutions 


Part  I 


x  half-size) ) 
y  half-size) ) ) 


1.  (defun  draw-square  (window  x  y  size) 

(let*  ((half-size  (//  size  2)) 

(xO  (-  x  half-size))  (x1  (+ 

(yO  (-  y  half-size) )  (y1  (+ 

(send  window  :draw-line  xO  yO  xO  y1 ) 

(send  window  : draw- line  xO  y1  x1  y1 ) 

(send  window  : draw-line  x1  y1  x1  yO ) 

(send  window  :draw-line  x1  yO  xO  yO ) ) ) 

(defun  draw-square  (window  x  y  size) 
(let*  ((half-size  ( //  size  2)) 

(xO  (-  x  half-size))  (x1  (+  x  half-size)) 
(yO  (-  y  half-size))  (y1  (+  y  half-size))) 
(send  window  : draw-lines  tv:alu-ior 

xO  yO  xO  y1  x1  y1  x1  yO  xO  yO ) ) ) 

2.  (def flavor  my-window  ( ) 

(tv: window) ) 

(def method  (my-window  : draw-square)  (x  y  size) 
(draw-square  self  x  y  size)) 

3.  (defvar   *square-size*    100) 


(def method    (my-window    : draw- square) 

(x  y  &.optional    (size    *square-size* 
(draw-square    self   x  y   size)) 


4.     (def method    (my-window    : mouse-click 
(cond    ((=   buttons   #\mouse-l-1) 

(send   self    : draw-square    ( 


(buttons   x  y, 


5.        A. 


t) 


(t  nil))) 


x  tv: lef t-margin-size ) 
(-   y  tv: top-margin-size) ) 
prevent  other  .mouse-click  methods 

from  being  called  (:or  combination) 
allow  other  kinds  of  clicks  to  fall  through 


It  doesn't  work  because  the  : mouse-click  method  is  called  from 
the  mouse  process,  and  different  processes  each  have  their  own  variable 
binding  stacks.  The  mouse  process  can  see  the  global  value  of 
*square-size*  (100)  which  was  set  by  the  defvar,  but  not  the  let  bind- 
ing (50)  which  is  in  the  binding  stack  of  your  lisp  listener.    (There  is 


Section  2.8  Problem  Set  #2  39 


more  information  on  processes  in  the  next  chapter.) 

B.  (let-globally  ( ( *square-size*  50)) 
(process-sleep  300)) 

6.  (def flavor  my-window 

( (default-square-size  100 ) ) 
(tv: window) 
: settable-instance-variables ) 

(def method  (my-window  : draw-square )  (x  y  ^optional  size) 
; ;  can't  default  the  optional  arg  because  environment 
; ;  isn't  set  up  yet  -  use  "or"  in  body 
(draw-square  self  x  y  (or  size  default-square-size))) 

7.  (let  ((old-size  (send  w  :def ault-square-size) ) ) 

( unwind-protect 

(progn  (send  w  : set-default-square-size  50) 
(process-sleep  300)) 
(send  w  : set-default-square-size  old-size))) 

kwc-letf,  a  macro  written  by  Ken  Church,  does  just  this  sort  of  thing,  and 
looks  a  lot  nicer.  (Its  name  was  chosen  to  distinguish  it  from  letf,  a  special 
form  provided  by  Symbolics  which  has  similar,  but  slightly  different,  effects.) 
The  syntax  is  like  that  of  let,  except  in  place  of  the  names  of  local  variables 
to  be  bound,  kwc-letf  accepts  any  reference  which  can  be  understood  by  setf. 
It  arranges  for  that  reference  to  return  the  specified  value  if  called  within  the 
kwc-letf,  and  for  the  old  value  to  be  restored  upon  exiting.  In  our  case,  it 
would  be  used  like  this: 

(kwc-letf  (((send  w  :def ault-square-size )  50)) 
(process-sleep  300)) 

This  produces  identical  compiled  code,  but  makes  the  intent  much  clearer  — 
you  can  see  that  I  just  want  to  evaluate  the  process-sleep  in  a  context  where 
(send  w  :def ault-square-size)  would  return  50.  The  call  to  kwc- 
letf  macroexpands  into: 

(LET  ((#:G0531  (SEND  W  : DEFAULT-SQUARE-SIZE) ) ) 
(UNWIND-PROTECT 

(PROGN  (SEND  W  ': SET-DEFAULT-SQUARE-SIZE  50) 
(PROCESS-SLEEP  300)) 
(PROGN  (SEND  W  ': SET-DEFAULT-SQUARE-SIZE  #:G0531)))) 


40  WHAT'S  A  FLAVOR?  Chapter  2 


8.  (def flavor  doubling -window  () 
(my-window) ) 

(defwhopper  (doubling-window  : draw-square)  (x  y  ^optional  size) 
(continue -whopper  x  y  (if  size  (*  2  size) 

(*  2  default-square-size)))) 

An  alternative  whopper  would  be: 

(defwhopper    (doubling-window    :draw-square)    (x  y  &.optional   size) 
(let    ((default-square-size    (*   2   default-square-size))) 
(continue-whopper  x  y   (and  size    (*   2   size))))) 

Part  II 

1 .  Here  is  a  simple-minded  implementation: 

(defun  sort-handlers  ( object- 1  object-2) 
(loop 

for  message  in  (union  (send  object- 1  :which-operations) 

(send  object-2  :which-operations) ) 
for  handler- 1  =  (send  object- 1  :get-handler-for  message) 
for  handler-2  =  (send  object-2  :get-handler-for  message) 
when  (not  handler-2)  collect  handler- 1  into  only-1 
else  when  (not  handler-1)  collect  handler-2  into  only-2 
else  when  (eq  handler-1  handler-2)  collect  handler-1 

into  both-and-same 
else  collect  (cons  handler-1  handler-2) 

into  both-and-dif f erent 
finally  (return  (list  only-1  only-2 

both-and-same  both-and-dif f erent) ) ) ) 

2.  A  partial  answer:  everything  you  need  to  know  about  a  flavor  is  in  the  list 
returned  by  (si: examiner-compute-magic-list  (get  flavor -name 
'si : flavor)  ).  The  extraction  of  the  info  is  done  by  the  method 
:compute-all-handlers-once  of  the  flavor  flavex:flavor.  As  for  M-x 
List  Combined  Methods,  the  crucial  function  is  zwei:find-combined-methods 

3.  To  follow  up  the  describe  hint,  this  is  what  describe  uses: 

(cdr  (assq  :fdef inition-location-hints 
( si : cca-extra-inf o 

(si:compiled-function-cca  function-obj) ) ) ) 


Section  2.8  Problem  Set  #2  41 


So  we  might  replace  this  line  in  my  answer  for  (1): 

else  when    ( eq  handler- 1   handler-2)    collect  handler- 1 

into  both-and-same 

with: 

else   when    (or    (eq  handler- 1    handler-2) 

(equal    ( f oo  handler- 1)    ( f oo  handler-2))) 
collect  handler- 1    into  both-and-same 

where    (  f  oo  handler)  is: 

(cdr    (assq    : f definition-location-hints 
( si : cca-extra-inf o 

( si : compiled-f unction-cca  handler ) ) ) ) 

And  if  you  used  my  partial  answer  for  (2),  the  list  returned  by  shexaminer- 
compute-magic-list  still  contains  everything  you  need  to  know,  although  it's 
possible  your  answer  to  (2)  threw  away  some  of  the  information  needed  for 
(3). 

4.   At  the  moment,  this  is  an  open  problem   —   I  don't  know  exactly  what's 
required  to  make  such  an  addition.    But  it  sure  would  be  nice  to  have... 


Chapter  3 

MORE  ON  NAVIGATING  THE  LISP  MACHINE 


The  last  chapter  discussed  an  aspect  of  programming  with  the  lisp  language,  as 
implemented  on  the  lisp  machine.  This  one  is  about  some  aspects  of  using  the  lisp 
machine  which  are  more  or  less  independent  of  programming  on  it,  i.e.,  what  you 
might  call  the  operating  system  of  the  lisp  machine. 


3.1  The  scheduler  and  processes 

Switching  back  and  forth  among  the  different  processes  can  be  explicitly  controlled 
by  the  lisp  machine  programmer  (read  the  documentation  on  Stack  Groups),  but 
almost  never  is.  A  special  module  called  the  scheduler  generally  handles  this 
responsibility.  Every  l/60th  second  the  scheduler  wakes  up  and  decides  whether 
the  current  process  should  be  allowed  to  continue  running,  and  if  not,  which  other 
process  should  get  a  chance. 

If  the  current  process  has  been  running  continuously  for  less  than  a  second,  and 
wishes  to  continue,  it  is  allowed  to.  (Note  that  a  full  second  is  a  long  time  for  this 
sort  of  thing,  compared  to  other  timesharing  arrangements.)  Or  if  it's  been  running 
for  a  second  but  no  other  process  wishes  to  run,  it  is  still  allowed  to  continue.    But 


44  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


if  it's  been  monopolizing  the  machine  for  more  than  a  second,  and  one  or  more 
other  processes  want  to  run,  it's  forced  to  take  a  rest  while  the  scheduler  gives  the 
others  a  chance.  The  process  chosen  by  the  scheduler  is  now  treated  as  the  previ- 
ous current  process  was:  it  will  be  allowed  to  run  until  some  other  process  (es)  wish 
to  run  and  the  current  process  either  volunteers  to  give  the  others  a  chance,  or 
passes  the  one  second  mark. 

The  way  a  process  "volunteers  to  give  the  others  a  chance,"  or,  in  less  emotionally- 
laden  terms,  informs  the  scheduler  that  it  doesn't  need  to  run,  is  with  the  process- 
wait  function.  Process-wait  specifies  a  condition  the  process  is  waiting  for.  When 
the  condition  becomes  true,  the  process  is  ready  to  run.  When  the  scheduler 
decides  to  resume  the  process,  the  call  to  process-wait  returns  and  the  computation 
continues  from  there.  The  first  argument  to  process-wait  is  a  string  to  appear  in 
the  wholine  (at  the  bottom  of  the  screen)  while  the  process  is  waiting.  The  second 
arg  is  a  function  and  any  remaining  args  are  arguments  to  the  function.  To  see 
whether  the  process  is  ready  to  continue,  the  scheduler  applies  the  specified  func- 
tion to  the  specified  arguments.  The  return  value  of  the  function  is  what  the 
scheduler  uses  for  the  "condition"  mentioned  above.  This  function  is  often  called 
the  process'  wait -function.  Here  is  the  process- wait  which  is  responsible  for  "Tyi" 
appearing  in  the  wholine  most  of  the  time: 

(PROCESS-WAIT  "Tyi"  SELF  ':LISTEN) 

This  call  is  buried  somewhere  in  the  code  windows  (or  anything  with  tv:stream- 
mixin)  use  for  reading  from  the  keyboard.  It  says  that  the  process  will  be  ready  to 
continue  when  application  of  SELF  to  the  argument  : LISTEN  returns  non-nil. 
Since  funcall  is  equivalent  to  send  when  dealing  with  instances  (see  the  previous 
chapter),  this  process-wait  will  return  when  (send  self  :  listen)  is  true. 
The  handler  for  .listen  just  checks  to  see  if  anything  is  in  the  io-buffer,  so  the  pro- 
cess which  calls  this  process-wait  will  forfeit  its  turns  in  the  scheduler  until  it  has 
something  in  its  io-buffer. 

Now  a  question  for  the  bold:  what  happens  if  an  error  occurs  in  the  scheduler?  It 
is,  after  all,  just  another  piece  of  lisp  code.  And  even  if  the  scheduler  code  itself  is 
bug-free,  all  the  wait-functions  are  called  in  the  scheduler,  and  any  loser*  can 
write  a  buggy  wait-function.  It's  also  the  case  that  blinking  of  flashing  blinkers 
gets  done  from  the  scheduler.  (There's  a  clock  function  list  of  things  to  be  done 
every  time  the  scheduler  runs,  and  by  default  the  only  thing  on  the  list  is  blinking 
the  blinkers.)  And  any  loser  can  also  write  a  buggy  :blink  method  for  his/her 
blinkers  —  I've  certainly  done  it.   So  what  happens  when  the  scheduler  runs  into  an 


See  hacker's  definition  at  end  of  chapter. 


Section  3.1  The  scheduler  and  processes  45 


error?  The  scheduler  has  no  window  to  use.  How  can  the  debugger  communicate 
with  you? 

What  happens  is  that  the  scheduler  enters  the  debugger  and  uses  what  is  called  the 
cold-load  stream.  This  is  a  very  basic  stream  which  completely  bypasses  the  win- 
dow system.  It  uses  the  screen  as  it  would  a  dumb  terminal,  with  no  regard  for  the 
previous  display  contents,  ignoring  even  window  boundaries.  There  will  be  no 
blinker  (which  makes  typing  somewhat  disconcerting)  and  none  of  the  input  editor 
commands  will  be  active,  apart  from  the  rubout  key.  But  you  will  be  in  a  legiti- 
mate debugger,  from  which  you  can  attempt  to  set  things  right.   So  don't  panic. 

Our  view  of  scheduling  is  now  fairly  complete.  The  current  process  owns  the  lisp 
machine  until  it  either  does  a  process-wait,  or  uses  up  its  second.  When  either  of 
these  occurs,  the  scheduler  calls  the  wait-functions  of  the  other  processes.  The  first 
process  whose  wait-function  returns  a  non-nil  value  gets  to  become  the  current- 
process.  If  none  of  them  do,  the  old  current  process  remains  the  current  process. 
And  if  any  errors  occur  while  in  the  scheduler,  the  debugger  uses  the  cold-load 
stream. 

Fine.  Now  it's  time  to  complicate  things  again.  At  any  given  time  a  process  is 
either  active  or  inactive.  Inactive  processes  are  not  even  considered  by  the  scheduler 
when  it  looks  for  an  alternative  to  the  current  process.  Their  wait-functions  aren't 
called  at  all  until  they  become  active.  And  what  makes  a  process  active  or  inac- 
tive? Two  of  the  instance  variables  of  a  process  are  its  run-reasons  and  its 
arrest -reasons.  An  active  process  is  one  with  no  arrest  reasons  and  at  least  one  run 
reason.  Otherwise  (at  least  one  arrest  reason  or  no  run  reasons)  the  process  is  inac- 
tive. There  are  messages  for  looking  at  a  process'  run  and  arrest  reasons,  and  for 
adding  to  or  deleting  from  them.  A  program  might  use  those  messages,  but  an 
interactive  user  is  more  likely  to  arrest  or  un-arrest  a  process  in  one  of  the  follow- 
ing ways  (all  of  which  end  up  passing  those  same  messages,  but  are  easier  to  use) : 

1.  The  system  menu  has  options  for  arresting  or  un-arresting  the  process  in  the 
window  the  mouse  is  over. 

2.  If  you  click  on  the  name  of  a  process  in  Peek's  display  of  processes,  you  get  a 
menu  of  useful  things  to  do  to  that  process.  Two  of  them  are  arresting  and 
un-arresting. 

3.  Typing  Function- A  arrests  the  process  the  wholine  is  watching.  (This  is  usu- 
ally the  selected  window's  process.  But  you  can  change  which  process  the 
wholine  watches  with  Function-W.)    Function-minus-A  un-arrests  it. 

Another  common  operation  to  perform  on  a  process  is  to  reset  it.  This  is  very 
much  like  typing  c-m-Abort  to  it.    It  flushes  everything  on  the  process'  stack  and 


46  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


restarts  it.  (More  exactly,  it  reapplies  the  process'  initial  function  to  its  initial 
arguments,  but  you  needn't  understand  that  just  yet.)  You  can  only  type  c-m- 
Abort  to  a  process  when  you  can  select  its  window,  which  isn't  always  possible,  but 
you  can  reset  a  process  anytime.  The  options  for  how  to  reset  a  process  are  similar 
to  those  for  un-/arresting  one.  You  can  send  a  process  the  :reset  message;  you  can 
use  the  reset  option  in  the  system  menu  to  reset  the  process  in  the  window  under 
the  mouse;  you  can  use  the  menu  in  Peek's  display  of  processes. 

Note  that  all  these  ways  of  resetting,  except  for  explicitly  sending  the  :reset  mes- 
sage, depend  on  being  able  to  use  the  mouse.  So  if  the  mouse  process  is  the  one 
which  is  in  trouble,  they  won't  work.  The  only  way  out  is  to  get  a  handle  on  the 
mouse  process  and  send  it  the  :reset  message.  An  extremely  useful  fact  to 
remember  is  that  the  value  of  the  symbol  tv:mouse-process  is  always  the  mouse  pro- 
cess itself  (an  instance  of  flavor  si:process).  So  typing  this  will  often  unwedge  the 
mouse  process:     (send  tv: mouse-process    :reset). 

One  final  note  on  resetting:  (send  current-process  : reset)  doesn't  work. 
(It  just  returns  nil.)  The  usual  method  for  unwinding  a  stack  doesn't  work  from 
within  that  stack.  To  reset  the  current  process,  you  need  to  either  spawn  a  new 
process  for  the  sole  purpose  of  resetting  your  process  (use  process-run-function) ,  or 
use  an  optional  argument  to  the  reset  message:  (send  current-process 
:  reset    :  always  )  will  work. 

Before  long  you  will  probably  have  cause  to  create  your  own  processes.  Take  a 
look  at  Part  III  of  Volume  8  of  the  Symbolics  documentation  when  the  need  arises. 


3.2  Windows 

The  entire  set  of  existing  windows  is  organized  into  several  trees.  The  root  of  each 
tree  is  a  screen.  (Screens  are  built  on  tv:sheet  but  don't  have  all  the  other  mixins 
that  make  a  window.)  Each  window  has  a  superior  (towards  the  root  of  the  tree) 
and  any  number  (possibly  0)  of  inferiors  (towards  the  leaves) .  The  windows  option 
in  Peek  displays  all  the  trees  (subject  to  a  restriction  mentioned  below). 

The  state  of  a  window  may  be  characterized  in  any  of  several  ways.  The  window 
may  be  selected  or  deselected,  it  may  be  exposed  or  deexposed,  and  it  may  be 
activated  or  deactivated.  The  terminology  is  confusing  and  unfortunate.  Selection, 
exposure,  and  activation  are  not  independent  factors.  In  fact,  they  are  closely  tied. 
Before  a  window  may  be  selected,  it  must  be  exposed.  And  before  it  may  be 
exposed,  it  must  be  activated.  So  there  are  four  possible  states  for  a  window: 
deactivated;  activated  but  not  exposed  (usually  called  deexposed);  activated  and 


Section  3.2  Windows  47 


exposed  but  not  selected  (usually  called  exposed);  and  activated,  exposed,  and 
selected  (usually  called  selected). 

If  a  window  is  deactivated,  the  system  will  not  keep  track  of  it.  More  precisely,  the 
window  will  not  appear  in  the  array  which  is  the  value  of  tv:previously-selected- 
windows.  Many  parts  of  the  system  software,  including  Peek,  use  that  array  when 
they  are  expected  to  produce  a  list  of  all  windows.  And  a  deactivated  window  will 
not  appear  in  the  inferiors  list  of  its  superior.  The  system  will  not  keep  any 
pointers  to  such  a  window,  so  unless  you  have  one,  the  window  will  be  garbage- 
collectible.    (Ignore  this  point  for  now  if  you  don't  understand  garbage  collection.) 

Once  activated,  a  window  may  become  exposed.  Being  exposed  means  roughly  that 
the  window  has  somewhere  for  its  typeout  to  go.  Any  window  which  is  completely 
visible  on  the  screen,  not  even  partly  covered  by  some  other  window,  is  exposed.  (It 
is  also  possible  for  windows  to  be  exposed  without  being  visible.  Such  a  window 
must  have  somewhere  for  its  typeout  to  go  other  than  your  screen  —  that  place 
would  be  a  bit-array  which  could  later  be  mapped  onto  the  screen.  See  sections 
11.4  and  11.5,  Pixels  and  Bit-save  Arrays,  and  Screen  Arrays  and  Exposure,  in 
Volume  7.    For  now  let's  just  assume  that  only  visible  windows  are  exposed.) 

If  a  window  which  is  not  exposed  is  asked  to  type  something  out  (perhaps  with  the 
:tyo  or  :string-out  messages),  it  won't  be  able  to  do  it,  since  it  has  no  place  to  send 
the  typeout.  How  it  reacts  is  controlled  by  its  deexposed -typeout -action,  which  is 
an  instance  variable  of  tv:sheet.  It  may  specify,  for  instance,  that  the  window 
should  try  to  expose  itself,  or  that  an  error  should  be  signaled.  The  default  value  of 
deexposed-typeout-action,  :  normal,  specifies  that  the  process  doing  the  typeout 
should  enter  an  output  hold  state.  That  means  it  will  do  a  process-wait  (remember 
those?)  with  a  wholine  state  of  "Output  Hold"  and  a  wait-function  which  essen- 
tially waits  for  the  window  to  become  exposed: 

(PROCESS-WAIT  "Output  Hold" 

#' (LAMBDA  (SHEET) 

(NOT  (SHEET-OUTPUT-HELD-P  SHEET))) 
SELF) 

In  addition  to  the  usual  ways  of  exposing  the  window  (mentioned  below),  when  an 
output  hold  occurs  there  is  one  extra  way  which  becomes  available.  That  is  to  type 
Function-Escape. 

Now  for  selection.  Although  any  number  of  windows  may  be  simultaneously 
exposed,  as  long  as  they  can  all  fit  on  your  screen  without  overlapping,  only  one 
window  at  a  time  may  be  selected.    The  currently  selected  window  is  always  the 


48  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


value  of  the  symbol  tv:selected-window.  The  selected  window  is  the  one  to  which 
keyboard  input  is  directed.  It  usually  has  a  blinking  rectangular  cursor  in  it. 
There  must,  of  course,  be  a  process  running  in  the  selected  window  for  it  to  do  any- 
thing with  the  keyboard  input.  If  the  selected  window  has  no  process,  typing  on  the 
keyboard  has  no  effect,  except  for  special  keys  like  Function  and  Select. 

If  we  imagine  the  four  possible  window  states  (deactivated,  deexposed,  exposed, 
selected)  occupying  a  spectrum,  the  various  messages  for  changing  the  state  of  a 
window  may  be  pictured  as  follows: 


ACTIVATION     EXPOSURE       SELECTION 


DEACTIVATED 


DEEXPOSEO 


EXPOSED 


SELECTED 


ACTIVATE 

EXPOSE 

SELECT 


DEACTIVATE 

DEEXPOSE 

DESELECT 


Figure  3.  Transitions  among  window  states 


The  meaning  of  the  arrows  is  that  a  window  sent  the  given  message  will  be  pushed 
all  the  way  from  its  current  state  to  the  head  of  the  arrow.  So,  for  instance,  if  an 
exposed  window  is  sent  the  :deactivate  message,  it  will  be  both  deexposed  and  deac- 
tivated. A  selected  window  would  be  deselected,  deexposed,  and  deactivated.  The 
messages  only  push  in  the  direction  of  the  arrows,  they  don't  pull.  That  is,  if  the 
window  is  already  at  or  beyond  the  arrowhead  nothing  happens.  If  a  selected  win- 
dow is  sent  the  :activate  message,  there  is  no  effect.  It  is  not  pulled  back  to  the 
deexposed  state. 

A  freshly  instantiated  window,  as  is  returned  by  tv:make-window,  will  be  deac- 
tivated, unless  you  specify  otherwise.  This  is  also  the  state  of  a  window  which  has 
been  sent  the  deactivate  or  :kill  messages.  (Killing  a  window  deactivates  all  of  its 
inferiors  as  well  as  itself.) 

You  can  always  change  the  state  of  a  window  by  sending  it  an  appropriate  mes- 
sage, but  there  are  several  ways  to  make  these  messages  be  sent  without  explicitly 
sending  them  yourself.    The  system  menu  has  an  option  for  killing  the  window 


Section  3.2  Windows  49 


under  the  mouse,  and  one  for  selecting  a  window  from  the  list  in  tv:previously- 
selected-windows.  The  Edit  Screen  option  in  the  system  menu  pops  up  another 
menu  with  options  for  killing  or  exposing  any  partially  visible  window,  and  for 
exposing  any  window  in  tv:previously-selected-windows.  (The  Edit  Screen  menu 
also  has  options  for  creating,  moving,  or  reshaping  windows.)  And  if  you  click  on 
the  name  of  a  window  while  in  the  windows  display  of  Peek,  you  get  a  menu  with 
options  for  selecting,  deselecting,  exposing,  deexposing,  deactivating  or  killing  the 
window. 

There's  another  way  to  select  a  window  which  you  are  already  familiar  with:  use 
the  Select  key.  For  the  kinds  of  windows  accessible  via  the  Select  key  (Select-Help 
displays  a  list),  the  effect  of  the  Select  key  depends  on  how  many  instances  of  that 
flavor  of  window  exist.  Let's  take  Select-E  (for  the  Zmacs  Editor)  as  an  example. 
If  there  are  no  existing  Zmacs  windows,  typing  Select-E  will  create  one  and  select 
it.  If  there  is  exactly  one  Zmacs  window,  Select-E  will  select  it  (unless  it  is  already 
the  selected  window,  in  which  case  the  screen  will  flash  and  it  will  remain  the 
selected  window) .  If  there  are  more  than  one  existing  Zmacs  windows,  and  none  of 
them  are  the  selected  window,  Select-E  will  select  the  one  which  had  most  recently 
been  the  selected  window.  Typing  Select-E  repeatedly  will  rotate  through  all  the 
existing  Zmacs  windows. 

Typing  Select-c-E  (hold  down  the  control  key  while  striking  E)  will  always  create 
and  select  a  new  Zmacs  window,  regardless  of  whether  there  are  already  some. 

Windows  can  also  be  selected  with  the  Function  key.  Function-S  selects  the  previ- 
ously selected  window.  Providing  a  numeric  argument  between  the  Function  key 
and  S  allows  rotation  of  the  selected  windows  in  various  arcane  ways.  Type 
Function-Help  and  read  about  S  for  a  full  description. 

Changing  the  state  of  a  window  will  often  cause  the  state  of  other  windows  to 
change.  For  instance,  if  I  select  one  window,  the  window  which  had  been  selected 
necessarily  becomes  deselected.  And  if  I  deselect  a  window,  some  other  window 
(the  previously  selected  one)  becomes  selected.  Similarly,  exposing  a  window  may 
partially  or  entirely  cover  some  other  window  which  had  been  exposed;  the  latter 
window  is  forced  to  become  deexposed.  And  deexposing  a  window  may  uncover 
some  other  window,  thereby  exposing  it.  (A  subtler  point  arises  here.  Simply  send- 
ing the  :deexpose  message  usually  does  not  have  the  intended  effect.  Since  no  other 
windows  will  be  covering  the  one  which  has  just  been  deexposed,  it  will  immedi- 
ately be  automatically  re-exposed.  It  will  look  like  nothing  happened.  What  you 
probably  meant  to  do  was  either  expose  some  other  window  [which  will  automati- 
cally deexpose  the  first  window],  or  send  the  first  window  the  :bury  message,  which 
in  addition  to  deexposing  it,  puts  the  window  underneath  all  the  other  windows,  so 


50  MORE  ON  NA  VIGA  TING  THE  LISP  MACHINE  Chapter  3 


that  the  window  that  ends  up  being  auto-exposed  is  some  other  one.) 

The  interactions  among  windows  can  become  terribly  convoluted.  There  are  several 
kinds  of  locks  intended  to  keep  everything  straight.  If  something  goes  wrong  and 
an  error  occurs  while  the  window  system  is  locked,  the  debugger  won't  be  able  to 
expose  a  window  to  use.  So  it  uses  the  cold-load  stream,  just  as  when  an  error 
occurs  inside  the  scheduler. 

If  you've  been  messing  with  the  window  system  in  unwise  ways,  it's  possible  to  get 
it  locked  up  so  that  you  can't  do  anything  (I  do  it  all  the  time).  If  the  window 
which  appears  to  be  selected  isn't  responding  to  typein,  and  c-m-Abort  doesn't  help, 
and  the  mouse  is  dead,  and  you  can't  select  some  other  window  with  the  Select  or 
Function  keys,  it  may  be  that  you're  hung  up  in  a  locked  window  system.  Your 
last  resort  in  such  a  case  (short  of  h-c-Function  and  a  warm  or  cold  boot)  is  to  type 
Function-control-Clear  Input.  This  clears  all  the  locks  in  the  window  system.  It's 
a  sledgehammer,  and  can  easily  break  some  things,  but  it  may  revive  your  machine 
without  having  to  boot. 

One  last  note  about  windows.  When  a  window  is  sent  more  than  one  screenful  of 
typeout  at  a  time,  it  may  pause  at  the  end  of  each  screenful,  type  **MORE**,  and 
wait  for  you  to  press  any  key  before  continuing.  This  behavior  is  called  more  pro- 
cessing. Whether  more  processing  occurs  (as  opposed  to  continuous  output)  is  con- 
trolled by  Function-M  and  Function-c-M.  Type  Function-Help  for  details.  For 
more  processing  to  occur  it  must  be  turned  on  both  globally  and  for  the  individual 
window. 


3.3  Debugging 

The  trace  feature  can  be  invaluable  in  finding  out  why  your  code  isn't  doing  what 
you  expected.  You  can  read  all  about  it  in  chapter  4  of  volume  4.  The  basic  form 
works  like  this:  you  turn  on  tracing  for  a  function  named  foo  by  evaluating 
(trace  foo).  From  then  on,  every  time  foo  is  called,  a  line  will  be  printed  on 
your  screen  announcing  that  foo  has  been  entered  and  listing  its  arguments.  And 
when  foo  finishes  another  line  will  be  printed,  announcing  the  exit  from  foo  and 
listing  the  return  value(s).  You  turn  off  tracing  of  foo  with  (untrace  foo). 
Some  of  the  fancier  features  allow  you  to  print  the  values  of  arbitrary  expressions 
upon  function  entry  or  exit,  or  to  make  tracing  conditional  on  some  predicate,  or  to 
enter  a  break  loop  or  the  debugger  upon  entry.  The  syntax  for  these  features  can 
be  difficult  to  remember,  so  I'd  suggest  using  the  trace  menu  to  select  them.  (You 
get  the  trace  menu  by  clicking  on  trace  in  the  system  menu  or  by  doing  Meta-X 
Trace  in  the  editor.) 


Section  3.3  Debugging  51 


Trace  can  be  used  on  anything  you  can  describe  with  a  function  spec  (see  chapter 
27  of  volume  3).  Function  specs  are  most  often  symbols,  but  can  also  be  something 
like  (: method  tv:  sheet  : expose),  referring  to  the  :expose  method  for  flavor 
tv:sheet. 

One  note  of  caution:  you  can  instantaneously  make  your  machine  unusable  by 
tracing  the  wrong  function.  If,  for  instance,  you'd  traced  some  function  that  gets 
called  every  time  a  character  is  read  from  the  keyboard,  with  the  feature  that 
throws  you  into  the  debugger  upon  function  entry,  you'd  have  a  real  tough  time 
typing  "untrace."  (On  the  other  hand,  the  kinds  of  functions  that  can  break  every- 
thing when  traced  are  not  ones  the  new  user  is  likely  to  be  interested  in  anyway,  so 
don't  feel  inhibited  by  this  warning.  Go  ahead  and  play.  You  can  always  boot.  I 
just  thought  I  should  mention  that  I've  screwed  myself  this  way  more  than  once.) 

Advising  is  a  more  general  facility  similar  to  tracing.  Here  you  supply  an  arbitrary 
piece  of  code  to  be  executed  upon  function  entry  or  exit.  Advice  comes  in  three 
varieties:  before,  after  and  around.  The  three  kinds  are  very  much  like  before 
daemons,  after  daemons,  and  whoppers.  Advising  is  explained  in  detail  in  chapter 
4,  volume  4. 

The  debugger  itself  is  the  main  tool  for  discovering  what  went  wrong.  You  should 
remember  a  few  things  about  the  debugger  from  Chapter  1 :  it  is  entered  whenever 
an  error  occurs,  and  may  be  entered  manually  with  the  function  ( dbg )  or  by  typ- 
ing m-Suspend.  Once  in  the  debugger,  you  can  move  up  and  down  the  stack  with 
c-P  and  c-N  (for  previous  and  next),  and  see  the  whole  stack  with  c-B  (for  back- 
trace). There  are  generally  a  series  of  restart  handlers  bound  to  the  super  keys, 
and  to  Resume  and  Abort. 

Now  some  debugger  facilities  that  may  be  new.  The  arguments  of  the  function  in 
the  current  frame  are  accessible  via  the  function  dbg:arg.  It  takes  one  argument, 
specifying  which  of  the  current  function's  arguments  you  want  (you  may  specify 
either  by  name  or  by  number).  Suppose  the  current  function  has  an  argument 
named  "array,"  and  I  want  to  know  what  element  #5  in  the  array  is.  I  could  type 
(aref  (dbg:arg  'array)  5).  The  best  part  about  dbg:arg  is  that  it  can  be 
used  with  setf  to  change  the  argument.  So  if  the  first  argument  to  the  current 
function  were  the  string  "now"  and  I  wanted  to  change  it  to  the  string  "then",  I 
would  type  (  setf  (dbg:arg  0  )  "then"  ).  (Note  that  the  numbering  of  argu- 
ments begins  at  0,  not  1 .)  The  function  dbg:loc  is  analogous  to  dbg:arg,  but  works 
on  local  variables  instead  of  arguments. 

You  can  also  use  the  debugger  commands  c-m-A  and  c-m-L  to  get  the  values  of 
arguments  and  local  variables.    Returning  to  the  case  where  I  wanted  to  see 


52  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


element  #5  of  an  array  which  was  an  argument  in  the  current  frame,  I  could  type 
(assuming  the  array  were  the  third  argument)  c-2  c-m-A,  which  would  return  the 
array  object  and  give  me  a  fresh  debugger  prompt,  then  (aref  *  5),  using  *  to 
access  the  previously  returned  value. 

Once  you've  re-arranged  the  arguments  to  your  liking,  you  may  use  c-m-R  to  rein- 
voke  the  current  frame  with  the  new  arguments.  Another  useful  command  is  c-R, 
for  returning  a  specified  value  from  the  current  frame  (the  value  is  prompted  for 
after  you  type  c-R). 

Another  handy  command  is  c-E.  It  finds  the  definition  of  the  function  in  the 
current  frame  and  reads  it  into  the  editor.  (Of  course,  it  reads  the  whole  file  the 
function  is  defined  in.  You  will  be  positioned  in  the  buffer  at  the  place  where  the 
function  is  defined.)  Finally,  c-M  (for  mail)  will  set  you  up  for  sending  a  bug 
report.  You'll  be  switched  to  a  mail  window,  with  both  a  complete  stack  backtrace 
and  information  on  what  version  of  the  system  software  is  running  on  your  machine 
inserted  as  the  initial  contents  of  your  message.  Add  whatever  text  is  necessary  to 
describe  the  situation.  Check  the  top  line  of  the  buffer  to  make  sure  the  "To:"  field 
contains  the  name  of  an  appropriate  recipient,  and  edit  it  if  necessary.  Then  just 
hit  the  End  key.  (c-End  if  you  have  the  Bell  Labs/Murray  Hill  standard  utilities 
—  we  use  End  for  another  editing  function.)  Off  goes  your  mail,  you  get  returned 
to  the  debugger,  and  you  may  continue  as  you  please.  The  inclusion  of  the  back- 
trace makes  life  much  easier  for  your  system  maintainer. 


3.4  Who  Does  What 

Here  are  a  hodge-podge  of  lisp  functions  for  finding  out  about  functions  and  sym- 
bols (see  "Poking  Around  in  the  Lisp  World,"  section  17.1  in  volume  1,  for  some 
more):  who-calls  takes  one  argument,  usually  a  symbol.  It  searches  all  defined 
functions  and  collects  those  which  call  the  symbol  as  a  function  or  use  it  as  a  vari- 
able or  constant.  This  takes  a  long  time.  You  can  limit  the  search  to  certain  pack- 
ages by  using  the  optional  arguments  to  who-calls.  Apropos  takes  one  argument,  a 
string,  and  finds  all  symbols  whose  print-names  include  the  string  as  a  substring. 
This  also  takes  a  long  time,  and  also  can  be  limited  to  certain  packages  by  using 
the  optional  arguments.  Disassemble  takes  one  argument,  the  name  of  a  compiled 
function  or  the  function  object  itself.  It  prints  a  human-readable  version  of  the 
compiled  instructions.  Grindef  pretty-prints  the  definition  of  a  non-compiled  (inter- 
preted) function. 

See  also  the  Zmacs  Meta-X  commands  List  Callers,  Edit  Callers,  Function  Apro- 
pos, List  Combined  Methods,  Edit  Combined  Methods,  List  Methods,  and  Edit 


Section  3.4  Who  Does  What  53 


Methods. 

Section  17.1.1  of  volume  1  also  describes  some  variables  whose  values  are  automati- 
cally maintained  by  the  lisp  command  loop.  *,  for  instance,  is  always  bound  to  the 
value  returned  by  the  last  form  you  typed  in,  and  can  be  extraordinarily  helpful. 


3.5  The  Input  Editor  and  Histories 

The  input  editor  is  active  in  most  contexts  outside  of  the  editor.  Most  notably,  it  is 
active  when  you're  typing  to  a  lisp  listener.  c-Help  lists  all  the  input  editor  com- 
mands. Most  of  them  are  similar  to  the  Zmacs  commands,  so  you  can  do  all  sorts 
of  editing  of  the  input  before  it  gets  to  the  lisp  reader.  Two  of  the  more  helpful 
features  of  the  input  editor  are  the  histories  it  keeps,  the  input  history  and  the  kill 
history.  Every  time  you  send  a  form  off  to  be  evaluated  by  a  lisp  listener,  the  form 
is  added  to  that  lisp  listener's  input  history.  (Each  lisp  listener  keeps  its  own  input 
history,  even  the  editor's  typeout  window.)  Pressing  the  Escape  key  will  display  the 
input  history  of  the  window  you  are  typing  to.  Every  time  you  delete  more  than 
one  character  of  text  with  a  single  command  (with,  for  example,  m-D,  m-Rubout, 
Clear  Input,  c-W,  c-K),  the  deleted  text  is  added  to  the  kill  history.  There  is  only 
one  kill  history;  it  is  shared  by  all  the  windows  which  use  the  input  editor,  and  also 
the  Zmacs  window  (s).   c-Escape  displays  the  kill  history. 

In  both  the  input  editor  and  in  Zmacs,  c-Y  yanks  the  most  recent  item  off  the  kill 
history  and  inserts  it  at  the  current  cursor  position.  You  can  select  an  earlier  ele- 
ment from  the  history  by  giving  c-Y  a  numeric  argument.  Typing  m-Y  immedi- 
ately after  a  c-Y  does  a  yank  pop;  it  replaces  the  text  which  has  just  been  yanked 
with  the  previous  element  from  the  history.  Repeatedly  typing  m-Y  will  rotate  all 
the  way  through  the  history.  Giving  m-Y  a  numeric  argument  will  jump  that  many 
items  in  the  history. 

Note  that  since  all  windows  share  the  same  kill  history,  it  provides  a  simple  way  of 
transferring  text  from  the  editor  into  a  lisp  listener:  just  push  the  text  onto  the  kill 
history  while  in  the  editor,  perhaps  with  c-W  or  m-W  or  a  mouse  command.  Then 
switch  to  a  lisp  listener,  type  c-Y,  and  presto!   There's  your  text. 

In  the  input  editor,  c-m-Y  yanks  from  the  input  history.  (c-C  also  has  this  effect. 
It  is  an  older  command  which  some  people  still  prefer  to  use.  I  find  c-m-Y  easier 
to  remember.)  m-Y  again  has  the  effect  of  rotating  through  the  history.  (m-C  is 
the  corresponding  older  command  —  you  used  to  need  different  commands  for 
rotating  through  the  kill  history  and  the  input  histories,  but  now  m-Y  does  both.) 


54  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


In  Zmacs,  c-m-Y  has  the  effect  of  yanking  from  what's  called  the  command  his- 
tory, which  is  a  history  of  all  editing  commands  which  use  the  mini-buffer. 
Immediately  after  a  c-m-Y,  m-Y  has  the  usual  effect. 

The  ability  to  yank  previous  inputs  into  a  lisp  listener  raises  an  interesting  question: 
how  does  the  input  editor  know  when  you're  finished  editing  and  ready  for  the  input 
to  be  sent  off  to  lisp?  Normally,  if  you  just  type  your  input  without  any  yanking, 
the  input  editor  knows  you're  done  when  you  type  some  sort  of  delimiter  at  the  end 
of  the  input  string,  like  a  close  paren,  to  complete  a  well-formed  lisp  expression. 
But  if  you've  yanked  an  already  well-formed  expression,  how  can  you  complete  it? 
The  answer  is  that  there  is  a  special  activation  character.  It  is  the  End  key.  Press- 
ing End  while  anywhere  within  a  well-formed  expression  tells  the  input  editor 
you're  done,  and  it  sends  your  input  off  to  lisp.  So  if  you've  yanked  a  previous 
input  with  c-m-Y,  you  can  type  End  immediately  to  re-evaluate  the  same  expres- 
sion, or  you  can  edit  it  some  and  type  End  when  finished,  to  evaluate  the  modified 
expression. 

There's  one  other  input  editor  command  of  special  interest.  That's  c-sh-A,  which 
displays  the  argument  list  of  the  function  whose  name  you  have  typed.  So  if  I  type 
"(with-open-f  ile  "  to  a  lisp  listener,  and  then  type  c-sh-A,  the  following  will 
appear  on  my  screen: 

WITH-OPEN-FILE  (MACRO):  ((STREAM-VARIABLE  FILENAME  .  OPTIONS)  &BODY  BODY) 

c-sh-A  also  works  in  Zmacs. 


3.6  Fun  and  Games 

More   definitions   from    The  Hacker's   Dictionary    (Guy   L.   Steele   Jr.,   et   at), 
prompted  by  my  spontaneous  use  of  the  term  loser. 

LOSE  verb. 

1.  To  fail.   A  program  loses  when  it  encounters  an  exceptional  condition  or  fails 
to  work  in  the  expected  manner. 

2.  To  be  exceptionally  unaesthetic. 

3.  Of  people,  to  be  obnoxious  or  unusually  stupid  (as  opposed  to  ignorant).   See 
LOSER. 

DESERVE  TO  LOSE  verb.    Said  of  someone  who  willfully  does  THE 
WRONG  THING,  or  uses  a  feature  known  to  be  MARGINAL.    What  is 


Section  3.6  Fun  and  Games  55 


meant  is  that  one  deserves  the  consequences  of  one's  losing  actions.  "Boy, 
anyone  who  tries  to  use  UNIX  deserves  to  lose!" 

LOSE,  LOSE  interjection.  A  reply  or  comment  on  an  undesirable  situation. 
Example:   "I  accidentally  deleted  all  my  files!"   "Lose,  lose." 

LOSER  noun.  An  unexpectedly  bad  situation,  program,  programmer,  or 
person.  Someone  who  habitually  loses  (even  winners  can  lose  occasionally). 
Someone  who  knows  not  and  knows  not  that  he  knows  not.  Emphatic  forms 
are  "real  loser,"  "total  loser,"  and  "complete  loser." 

LOSS  noun.  Something  (but  not  a  person)  that  loses:  a  situation  in  which 
something  is  losing. 

WHAT  A  LOSS!  interjection.  A  remark  to  the  effect  that  a  situation  is  bad. 
Example:  Suppose  someone  said,  "Fred  decided  to  write  his  program  in 
ADA  instead  of  LISP."  The  reply  "What  a  loss!"  comments  that  the  choice 
was  bad,  or  that  it  will  result  in  an  undesirable  situation  —  but  may  also 
implicitly  recognize  that  Fred  was  forced  to  make  that  decision  because  of 
outside  influences.  On  the  other  hand,  the  reply  "What  a  loser!"  is  a  more 
general  remark  about  Fred  himself,  and  implies  that  bad  consequences  will 
be  entirely  his  fault. 

LOSSAGE  (lawss'.j)  noun.  The  stuff  of  which  losses  are  made.  This  is  a 
collective  noun.  "What  a  loss!"  and  "What  lossage!"  are  nearly  synonymous 
remarks. 


WIN 


1.  verb.  To  succeed.  A  program  wins  if  no  unexpected  conditions  arise.  Anto- 
nym:  LOSE. 

2.  noun.  Success,  or  a  specific  instance  thereof.  A  pleasing  outcome.  A 
FEATURE.  Emphatic  forms:  MOBY  win,  super-win,  hyper-win.  For  some 
reason  "suitable  win"  is  also  common  at  MIT,  usually  in  reference  to  a  satis- 
factory solution  to  a  problem.   Antonym:   LOSS. 

BIG  WIN  noun.  The  results  of  serendipity. 

WIN  BIG  verb.   To  experience  serendipity.    "I  went  shopping  and  won  big; 
there  was  a  two-for-one  sale." 

WINNER  noun.    An  unexpectedly  good  situation,  program,  programmer,  or 
person.   Albert  Einstein  was  a  winner.   Antonym:   LOSER. 

REAL  WINNER  noun.    This  term  is  often  used  sarcastically,  but  is  also 
used  as  high  praise. 


56  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


WINN  AGE  (win'.j)  noun.    The  situation  when  a  LOSS  AGE  is  corrected  or 
when  something  is  winning.   Quite  rare.   Usage:   also  quite  rare. 

WINNITUDE  (win':-tood)  noun.    The  quality  of  winning  (as  opposed  to 
WINNAGE,  which  is  the  result  of  winning) . 


Section  3.6  Fun  and  Games  57 


3.7  Problem  Set  #3 

Questions 

Evaluate  (make-system  'funny-window  rnoconfirm  :  silent).  This 
will  load  some  code,  and  create  and  select  a  window  of  flavor  funny-window,  mak- 
ing it  the  value  of  the  symbol  *  funny  -window*. 

The  funny-window  flavor  is  built  on  tvrlisp-listener,  so  you  can  type  forms  to  this 
window  and  it  will  evaluate  them  just  as  a  lisp  listener  would. 

This  window  has  two  behavioral  quirks,  one  which  occurs  just  before  it  types  out 
the  return  value  of  whatever  it  evaluates,  and  one  which  occurs  whenever  you  move 
the  mouse. 

The  assignment  is  to  find  out  what's  responsible  for  the  odd  behavior.  You  win  the 
game  if  you  can  get  the  code  causing  the  behavior  into  a  Zmacs  buffer.  Use  what- 
ever you  know  about  looking  into  the  state  of  the  lisp  machine.  Several  good  tech- 
niques are  buried  in  the  text  of  this  chapter. 

There's  one  restriction  on  what  you  may  do:  you  should  read  the  code  into  the  edi- 
tor by  using  some  system-provided  operation  which  finds  the  definition  of  a  given 
function.  So  you  have  to  first  figure  out  what  function  is  responsible.  It's  cheating 
to  randomly  read  in  files  and  scan  them. 

I  would  suggest  starting  on  the  typeout  quirk  —  it  should  be  a  little  easier  to  track 
down  than  the  mouse  behavior. 


58  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


Hints 

Note  that  there's  a  delay  partway  through  the  funny  typeout.  To  find  out  what's 
going  on,  you  can  simply  do  c-m-Suspend  during  the  delay  and  look  at  what's  on 
the  stack.  (At  this  point  you  might  want  to  (setq  *funny-typeout- 
delay*  0 )  for  the  duration.)  Use  c-E  on  the  appropriate  frame  to  pull  the 
offender  into  the  editor. 


Finding  the  mouse  funniness  isn't  as  easy.  c-m-Suspend  doesn't  work  —  and  not 
only  because  there's  no  time  for  it.  Try  setting  *funny-mouse-delay*  to  1  (sec). 
Now  there's  time  to  type  c-m-Suspend  during  the  funniness,  but  the  stack  shows 
nothing  revealing,  because  the  action  is  in  a  different  process.  (When  convinced, 
you  should  probably  set  *funny-mouse-delay*  back  to  0.) 

One  possible  way  to  proceed  would  be  to  put  a  trace  (with  :error)  on  the  :  draw- 
circle  method,  which  you  can  see  is  being  called.  [To  get  the  method  do 
(get-handler-for  *  funny- window*  :  draw-circle),  which  you  will  see 
turns  out  to  be  (: method  tv:graphics-mixin  : draw-circle) J.  That 
would  force  the  process  which  is  calling  : draw-circle  into  the  debugger. 
Unfortunately  everything  gets  fouled  up  when  the  mouse  process,  which  turns  out 
to  be  the  culprit,  goes  into  the  debugger.  (The  trouble  starts  because  the  mouse 
process  doesn't  have  a  window  to  use,  so  it  has  to  come  up  with  one  and  expose  it. 
That  in  itself  is  okay  [processes  which  run  in  the  background  generally  have  that 
capability],  but  the  real  killer  is  that  the  mouse  process  has  to  be  running  in  order 
for  most  ways  of  switching  windows  to  work.  With  the  mouse  process  halted  for 
debugging,  most  window  system  operations  are  impossible,  and  the  lisp  machine  is 
suddenly  in  a  terribly  wedged*  state!  (It  usually  isn't  necessary  to  re-boot  if  this 
happens  —  try  resetting  the  mouse  process,  with    (send    tv: mouse-process 


WEDGED  adjective. 

1 .  To  be  stuck,  incapable  of  proceeding  without  help.  This  is  different  from  having  CRASHED. 
If  the  system  has  crashed,  then  it  has  become  totally  nonfunctioning.  If  the  system  is 
"wedged,"  it  is  trying  to  do  something  but  cannot  make  progress.  It  may  be  capable  of  doing 
a  few  things,  but  not  be  fully  operational.  For  example,  the  system  may  become  wedged  if  the 
disk  controller  FRIES;  there  are  some  things  you  can  do  without  using  the  disks,  but  not  many. 
Being  wedged  is  slightly  milder  then  being  "hung."  This  term  is  sometimes  used  as  a  synonym 
for  DEADLOCKED.   See  also  HANG,  LOSING,  CATATONIA,  and  BUZZ. 

2.  Of  a  person,  suffering  severely  from  misconceptions.  Examples:  "He's  totally  wedged  —  he's 
convinced  that  he  can  levitate  through  meditation."  "I'm  sorry.  I  had  a  BIT  set  that  you  were 
responsible  for  TECO,  but  I  was  wedged." 

(The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  at) 


Section  3.7  Problem  Set  #3  59 


: reset).  If  you  can't  get  to  a  window  that  will  accept  typein,  do  Function- 
Suspend  first.) 

If  you  really  want  to  make  this  approach  work,  here's  something  a  little  more 
advanced  (that's  understated  —  it  took  two  of  us  quite  a  while  to  come  upon  it) 
that  will  produce  the  desired  effect: 

(advise    (: method  tv:graphics-mixin    : draw-circle)    : before  nil  nil 
(send   (send  * funny-window*    : process) 

: interrupt  #'dbg  current-process) 
(process-sleep  60.)) 


The  basic  idea  is  to  force  the  process  calling  :  draw-circle  into  the  debugger  by 
calling  the  dbg  function  on  it,  but  to  do  the  call  to  the  dbg  function  from  the  funny 
window,  using  its  process  and  its  already  exposed  and  selected  window.  Now  you 
can  examine  the  stack  and  quickly  find  the  : before  : mouse-moves  method 
which  is  responsible. 

But  there's  a  much  more  sensible  approach.  You  could  think  of  the  above  force-it- 
into-the-debugger  approach  as  finding  the  set  of  functions  which  are  being  called 
and  filtering  that  set  for  functions  which  seem  related  to  the  funny-window  flavor. 
Turning  that  around  is  far  more  effective  in  this  case.  That  is,  first  collect  the 
functions  related  to  the  funny-window  flavor,  which  is  much  easier  in  this  case  than 
getting  access  to  the  control  stack,  and  then  filter  that  set  for  ones  likely  to  be  caus- 
ing the  funny  effects.  So  one  idea  is  to  do  a  :which-operations  on  the  win- 
dow and  search  for  messages  with  suggestive  names.   You  could,  for  instance,  try 

(loop  for  msg  in  (send  * funny- window*  rwhich-operations) 
when  (string-search  "mouse"  msg)  collect  msg) 

[If  you  have  the  Murray  Hill  standard  utilities,  you  could  simply  do  (grep-msgs 
"mouse"  *  funny- window*).!  This  will  be  a  small  enough  set  that  they  could 
all  be  investigated.  A  more  direct  approach,  and  the  clear  winner  for  this  problem, 
is  based  on  the  observation  that  although  the  funny-window  flavor  has  many 
methods  defined,  the  bulk  of  them  are  inherited  from  other  flavors,  and  whatever  is 
responsible  for  its  peculiar  behavior  must  be  somewhere  in  the  relatively  small 
number  of  methods  defined  locally  for  funny- window.  So  all  you  have  to  do  is  enter 
the  Flavor  Examiner  (Select-X),  and  get  the  list  of  local  methods  for  funny- 
window.  How  about  that.  Two  methods,  one  for  each  peculiarity.  Now  you  can 
edit  them  either  by  clicking  mouse-right  while  pointing  to  one,  and  choosing  "edit" 
from  the  menu,  or  by  clicking  where  it  says  "edit"  on  the  extreme  right. 


60  MORE  ON  NAVIGATING  THE  LISP  MACHINE  Chapter  3 


Solutions 

Here's  what  causes  the  typeout  funniness: 

(defvar   *funny-typeout-delay*    1) 

; ; ;    You   found  the   funny  typeout   stuff ! 
(def whopper    (funny-window    : input-editor )    (krest   args ) 
(let    ((thing    ( lexpr-continue-whopper   args))) 

(format   self    "-&You  entered   something  of   type    ") 

(process-sleep    (*   60    *funny-typeout-delay* ) ) 

(princ    (typep  thing)    self) 

thing)) 


And  this  causes  the  mouse  funniness: 

(defvar   *funny-mouse-delay*   0) 

; ; ;  You  found  the  funny  mouse  stuff  I 

(def method  (funny-window  : before  : mouse-moves )  (x  y) 

(format  self  "-&The  mouse  is  moving  .  .  .  ") 

(process-sleep  (*  60  * funny-mouse -de lay* ) ) 

(send  self  : draw-circle 

(-  x  tv: left-margin-size)  (-  y  tv: top-margin-size )  8 

(send  self  :tyo  #\ ! ) ) 


Chapter  4 

FLOW  OF  CONTROL 


In  this  chapter  we  leave  behind  the  "operating  system"  of  the  lisp  machine  and 
return  to  aspects  of  the  lisp  language  itself.  In  particular,  we'll  look  at  the  various 
constructs  for  determining  the  flow  of  control.  The  notes  are  a  little  sketchier  than 
usual,  because  this  material  is  covered  reasonably  well  in  Part  V  of  volume  2  of  the 
Symbolics  documentation. 


4.1  Conditionals 

The  cond  special  form  is  the  basic  conditional.  The  arguments  to  cond  are  any 
number  of  clauses,  where  each  clause  is  a  list  containing  a  predicate  (the 
antecedent)  and  zero  or  more  consequents.  The  clauses  are  handled  one  at  a  time, 
in  order  of  appearance.  If  a  clause's  antecedent  returns  nil,  its  consequents  are 
skipped  and  the  next  clause  is  considered.  When  a  clause  is  found  whose 
antecedent  returns  a  non-nil  value,  that  clause's  consequents,  if  any,  are  all 
evaluated.  The  value  of  the  last  consequent  in  that  clause  (or  of  the  antecedent,  if 
there  are  no  consequents)  is  the  value  returned  by  the  cond,  and  the  rest  of  the 
clauses  are  skipped.   If  every  clause's  antecedent  returns  nil,  the  cond  returns  nil. 


62  FLOW  OF  CONTROL  Chapter  4 


Beyond  their  value  as  logical  operators,  and  and  or  can  also  be  used  as  conditionals. 
If  one  of  the  subforms  of  an  and  returns  nil,  the  rest  will  be  skipped.  And  if  one  of 
the  subforms  of  an  or  returns  non-nil,  the  rest  will  be  skipped.  Here  are  two  exam- 
ples taken  from  the  manual: 

(and  bright-day 

glorious-day 

(print  "It  is  a  bright  and  glorious  day.")) 

(or  it-is-f ish 
it-is-fowl 
(print  "It  is  neither  fish  nor  fowl.")) 

Almost  all  of  the  remaining  conditionals  are  really  macros  which  expand  into  calls 
to  cond.  when  and  unless  take  a  predicate  and  any  number  of  consequent  forms.  If 
the  predicate  for  a  when  returns  non-nil,  all  of  the  consequent  forms  are  evaluated 
and  the  value  returned  by  the  last  one  is  returned  by  the  when.  Otherwise  (a  nil 
predicate  value)  the  consequent  forms  are  all  skipped,  unless  works  similarly:  if 
the  predicate  returns  nil  the  consequents  are  evaluated,  otherwise  they're  skipped. 
Here  are  the  definitions  of  the  when  and  unless  macros: 

(DEFMACRO  WHEN  (TEST  &BODY  BODY) 
N ( COND  ( , TEST  ( PROGN  , @>BODY ) ) ) ) 

(DEFMACRO  UNLESS  (TEST  &BODY  BODY) 

"(COND  ((NOT  ,TEST)  (PROGN  ,@BODY) ) ) ) 

[Actually,  I  lied  a  bit  in  the  previous  paragraph.  Although  they  could,  and  in  fact 
used  to,  have  the  given  macro  definitions,  when  and  unless  are  now  special  forms 
instead.  I  used  the  old  macro  definitions  because  they're  easier  to  read,  while  for 
our  immediate  purposes,  any  differences  in  behavior  aren't  important.] 

Defining  suitable  macros  is  an  extremely  common  (and  effective)  method  for 
extending  the  syntax  of  lisp.  There  are  no  extra  levels  of  function  calling  at  run- 
time, and  no  modifications  to  the  compiler  are  involved. 

if  is  somewhat  similar  to  when,  and  also  macroexpands  to  a  call  to  cond.  If  the  test 
evaluates  to  non-nil,  the  first  body  form  is  evaluated.  Otherwise  (test  returns  nil), 
if  there  are  any  body  forms  following  the  first,  they  are  all  evaluated. 

Three  more  macros  based  on  cond  are  select,  selector,  and  selectq.  Selectq  is  used 
most  frequently.   Here  is  its  structure: 


Section  4.1  Conditionals  63 


( selectq  key-form 

(test  consequent  consequent  .  .  .  ) 
( test  consequent  consequent  .  .  .  ) 
( test  consequent  consequent  .  .  .  ) 
...) 

The  key-form  is  evaluated  and  checked  against  the  tests.  The  tests  are  not 
evaluated.  Each  test  must  be  either  a  symbol,  a  fixnum,  or  a  list  of  symbols  and 
fixnums.  If  the  test  (or  one  of  its  elements,  if  it's  a  list)  is  eq  to  the  evaluated  key- 
form,  then  it  matches.  The  symbols  t  and  otherwise  are  special:  a  test  consisting 
of  one  of  those  two  symbols  always  matches.  As  with  cond,  the  consequents  to  the 
first  test  which  matches  are  evaluated,  and  the  rest  of  the  clauses  are  skipped. 

Select  is  the  same  as  selectq,  except  that  the  symbols  in  the  tests  are  evaluated 
before  being  compared  to  the  (evaluated)  key-form.  Selector  is  like  select  except 
that  there  is  an  additional  argument  (following  the  key-form)  which  is  the  name  of 
a  function  to  use  for  the  comparison  in  place  of  eq. 

See  also  typecase,  dispatch,  cond-every,  and  selectq-every. 


4.2  Blocks  and  Exits 

block  is  the  primitive  for  defining  a  piece  of  code  which  may  be  exited  from  the 
middle.  The  first  argument  to  block  must  be  a  symbol.  It  is  not  evaluated,  and 
becomes  the  name  of  the  block.  The  rest  of  the  arguments  are  forms  to  be 
evaluated.  If  a  call  to  return-from  occurs  within  the  block,  with  a  first  argument  of 
the  block's  name,  the  block  is  immediately  exited.  The  rest  of  the  arguments  to 
return-from  are  evaluated  and  become  the  return  values  for  the  block.  (Beginning 
with  release  6.0,  the  preferred  way  of  returning  multiple  values  is  with  (return- 
from  name    (values  form... ) ),  for  compatibility  with  Common  Lisp.) 

The  scope  of  the  block  is  lexical,  so  the  corresponding  call  to  return-from  must 
occur  textually  within  the  block;  it  will  not  work  to  call  return-from  inside  a  func- 
tion which  is  called  within  the  block.  The  next  section  discusses  that  sort  of  nonlo- 
cal exit. 

Blocks  may  be  nested;  that's  the  whole  point  of  naming  them.  A  return-from 
causes  an  immediate  exit  from  the  innermost  block  with  a  matching  name. 

Some  other  constructs  (including  do  and  prog)  create  implicit  blocks.   These  blocks 


64  FLOW  OF  CONTROL  Chapter  4 


have  nil  for  a  name,  and  so  they  may  be  prematurely  exited  with  (return- 
from  nil  (values  value...)  ).  They  may  also  be  exited  with  the  return  special 
form,  which  always  exits  the  innermost  block  named  nil. 


4.3  Nonlocal  Exits 

catch  and  throw  are  analogous  to  block  and  return-from,  but  are  scoped  dynami- 
cally rather  than  lexically.  This  means  that  a  throw  may  cause  an  exit  from  any 
catch  on  the  control  stack  at  the  time  the  throw  is  reached  (unless  an  inner  catch  is 
shadowing  an  outer  catch  with  the  same  tag) .  catch's  equivalent  to  the  name  of  a 
block  is  its  tag.  The  tag  is  the  first  argument  to  catch;  it  is  evaluated,  and  may 
return  any  lisp  object.  The  first  argument  to  throw  is  its  tag.  It  is  also  evaluated, 
and  the  throw  causes  the  exit  of  the  innermost  catch  whose  evaluated  tag  is  eq  to 
the  throw's  evaluated  tag. 

If  a  throw  occurs,  its  second  argument  is  evaluated  and  the  value (s)  returned  will 
be  returned  by  the  corresponding  catch.  If  no  throw  occurs,  the  values  returned  by 
the  catch  are  the  values  returned  by  its  last  subform. 

There  are  obsolete  forms  of  catch  and  throw,  called  *catch  and  *throw.  They  differ 
from  the  newer  version  mainly  in  what  values  are  returned.  *catch  and  *throw 
should  not  be  used  in  new  code. 


4.4  Iteration 

There  are  three  styles  of  built-in  facilities  for  iteration.  A  group  of  operators  are 
available  for  mapping  a  function  through  one  or  more  lists;  the  do  special  form 
allows  more  general  forms  of  iteration;  and  the  loop  macro  provides  even  more 
flexibility.  (I  should  also  point  out  that  functions  which  make  use  of  tail  recursion 
are  compiled  into  iterative  structures.)  This  set,  of  course,  could  easily  be  extended 
by  writing  more  macros. 

When  more  than  one  of  the  iteration  facilities  is  applicable  to  a  particular  task,  the 
choice  is  mainly  a  matter  of  personal  taste.*  All  three  are  comparably  efficient. 
The  key  issue  is  readability,  and  on  this  score  opinions  differ.  My  own  view  is  that 
the  mapping  functions  are  succinct  and  to  the  point,  and  therefore  desirable,  within 
the  limited  set  of  applications  that  are  easily  expressed  as  mapping  operations.  For 
all  other  kinds  of  iteration,  do  is  often  concise  but  I  find  it  somewhat  obscure.1    I 


See  hacker's  definition  at  end  of  chapter. 


Section  4.4  Iteration  65 


think  loop  is  much  easier  to  read,  but  there  are  those  who  consider  it  wordy  and 
nebulous. 

"Loop  forms  are  intended  to  look  like  stylized  English  rather  than 
Lisp  code.  There  is  a  notably  low  density  of  parentheses,  and 
many  of  the  keywords  are  accepted  in  several  synonymous  forms  to 
allow  writing  of  more  euphonious  and  grammatical  English.  Some 
find  this  notation  verbose  and  distasteful,  while  others  find  it  flexi- 
ble and  convenient.   The  former  are  invited  to  stick  to  do." 

[The  preceding,  as  well  as  parts  of  the  discussion  of  loop  below,  is 
taken  from  the  loop  documentation  written  by  Glenn  S.  Burke: 
MIT  Laboratory  for  Computer  Science  TM-169.] 

For  the  sake  of  comparison,  here  are  four  ways  to  print  the  elements  of  a  list: 

(defun  print-eltsl  (list)         ;  mapc 
(mapc  #'print  list)) 

(defun  print-elts2  (list)         ;  do 
(do  ( (1  list  (cdr  1) ) ) 
((null  1)) 
(print  (car  1) )  )  ) 

(defun  print-elts3  (list)         ;  loop 
(loop  for  elt  in  list 
do  (print  elt) ) ) 

(defun  print-elts4  (list)         ;  tail  recursion 
(unless  (null  list) 
(print  (car  list)) 
(print-elts4  (cdr  list)))) 

4.4.1  Mapping 

The  mapping  operators  come  in  six  varieties.  They  all  take  as  arguments  a  func- 
tion followed  by  any  number  of  lists,  and  step  through  all  the  lists  in  parallel, 
applying  the  function  as  they  go.  They  vary  along  two  dimensions:  whether  they 
operate  on  successive  elements  of  the  lists  or  on  successive  sublists,  and  which  of 

t      ditto. 


66  FLOW  OF  CONTROL  Chapter  4 


three  kinds  of  values  they  return.  (Two  x  three  =  six.)  The  return  value  can  be 
simply  the  second  argument  to  the  mapping  operator  (implying  that  the  mapping 
was  done  for  side  effect  only),  or  a  list  of  the  results  of  function  application,  or  a 
list  formed  by  nconcing  (destructive  appending)  the  results  of  function  application. 
Here  are  a  few  examples: 

Applied  to  successive  elements,  lists  results 

(mapcar  #'  +    '(1    2   3   4)    '(2   4   6   8)) 
-(369    12) 

(mapcar  #'list    '(1    2   3   4)    '(2   4   6   8)) 

-  ((1    2)    (2   4)    (3    6)    (4   8)) 

Successive  elements,  nconcs  results 

(mapcan  #'list  '(1  2  3  4)  '(2  4  6  8)) 

-  (1224364   8) 

Successive  sublists,  lists  results 

(maplist  #'( lambda  (1)  (and  (second  1) 

(+  (first  1)  (second  1)))) 
'(1  2  3  4)) 
-(357  NIL) 

(maplist  #'( lambda  (1)  (list  (first  1)  (second  1))) 
'(1  2  3  4)) 

-  ((1  2)  (2  3)  (3  4)  (4  NIL)) 

Successive  sublists,  nconcs  results 

(mapcon  #'( lambda  (1)  (list  (first  1)  (second  1))) 
'(1  2  3  4)) 
-(1223344  NIL) 


4.4.2  Do 

A  do  looks  like  this: 
(do    (  ( var  init  repeat ) 


Section  4.4  Iteration  67 


( var  init  repeat )    .  .  .  ) 
{end-test  exit-form  exit-form    .  .  .  ) 
body -form  body -form    .  .  .  ) 

The  first  subform  is  a  list  of  index  variable  specifiers.  Upon  entering  the  do,  each 
var  is  bound  to  the  corresponding  init.  And  before  each  subsequent  iteration,  var  is 
set  to  repeat.  The  variables  are  all  changed  in  parallel.  The  end-test  is  evaluated 
at  the  beginning  of  each  iteration.  If  it  returns  a  non-nil  value,  the  exit -forms  are 
all  evaluated,  and  the  value  of  the  last  one  is  returned  as  the  value  of  the  do.  Oth- 
erwise the  body -forms  are  all  evaluated.  Here's  an  example  which  fills  an  array 
with  zeroes: 

(do  ((i  0  (1+  i)) 

(n  (array- length  foo-array) ) ) 
((=  i  n)) 
(setf  (aref  foo-array  i)  0)) 

Upon  entry,  i  is  bound  to  0  and  n  is  bound  to  the  size  of  the  anay.  On  each  itera- 
tion, i  is  incremented,  (n  stays  constant  because  it  has  no  repeat  form.)  When  i 
reaches  n,  the  do  is  exited.  On  each  iteration,  the  ith  element  of  foo-array  is  set  to 
0. 

And  another,  which  is  equivalent  to    (maplist  #'f  x  y): 

(do  ((x  x  (cdr  x)) 
(y  y  (cdr  y) ) 
(z  nil  (cons  (f  x  y)  z))) 
((or  (null  x)  (null  y) ) 
(nreverse  z) ) ) 

Note  that  the  preceding  example  has  no  body.  It's  actually  fairly  common  for  all 
the  action  in  a  do  to  be  in  the  variable  stepping. 

There  are  macros  named  dotimes  and  delist  which  expand  into  common  do  con- 
structs.  For  instance,  the  following  macroexpands  into  the  first  example  above: 

(dotimes  (i  (array-length  foo-array)) 
(setf  (aref  foo-array  i)  0)) 


68  FLOW  OF  CONTROL  Chapter  4 


4.4.3  Loop 

loop  is  a  macro  which  expands  into  a  prog  with  explicit  go  statements,  and  often 
with  several  lambda  bindings.   A  typical  call  looks  like  this: 

( loop  clause 
clause 
clause    .  .  .  ) 

Each  clause  begins  with  a  keyword,  and  the  contents  of  the  rest  of  the  clause 
depend  on  which  keyword  it  is.  Some  clauses  specify  variable  bindings  and  how  the 
variables  should  be  stepped  on  each  iteration.  Some  specify  actions  to  be  taken  on 
each  iteration.  Some  specify  exit  conditions.  Some  control  the  accumulation  of 
return  values.  Some  are  conditionals  which  affect  other  clauses.  And  so  on.  A  full 
discussion  of  all  the  clauses  would  be  lengthy  and  not  particularly  useful,  as  they're 
all  described  coherently  enough  in  the  documentation.  We'll  just  look  at  some 
representative  examples. 

The  repeat  clause  specifies  how  many  times  the  iteration  should  occur.  The  key- 
word is  followed  by  a  single  lisp  expression,  which  should  evaluate  to  a  fixnum. 
And  the  do  keyword  is  followed  by  any  number  of  lisp  expressions,  all  of  which  are 
evaluated  on  each  iteration.   So  putting  the  two  together, 

( loop  repeat  5 

do  (print  "hi  there")) 

prints  "hi  there"  five  times.  The  most  commonly  used  (and  complicated)  of  the 
iteration-driving  clauses  is  the  for  clause.  The  keyword  is  followed  by  the  name  of 
a  variable  which  is  to  be  stepped  on  each  iteration,  then  some  other  stuff  which 
somehow  specifies  the  initial  and  subsequent  values  of  the  variable.  Here  are  some 
examples: 

( loop  for  elt   in  expr         expr  is  evaluated  (it  better  return  a  list),  elt  is  bound  in 

do    (print  elt)  )        turn  to  each  element  of  the  list,  and  then  the  loop  is  exited 

( loop  for  elt  on  expr         similar,  but  elt  is  bound  to  each  sublist 
do    (print  elt) ) 

.  .  .    for  x  =  expr    .  .  .  expr  is  re-evaluated  on  each  iteration  and  x 

is  bound  to  the  result  (no  exit  specified  here) 

.  .  .    for  x   =  exprl    then  expr2    ...    x  is  bound  to  exprl  on  the  first  iteration 


Section  4.4  Iteration  69 


and  expr2  on  all  succeeding  iterations 

.    for  x  from  expr    ...        x  is  bound  to  expr  (it  better  return  a  fixnum)  on  the  first 
iteration  and  incremented  on  each  succeeding  iteration 

.    for  x  from  exprl   to  expr2    .  .  .    like  above,  but  the  loop  is  exited 

after  x  reaches  expr2 

.    for  x  from  exprl   below  expr 2    .  .  .    like  above,  but  the  loop  is  exited 

just  before  x  reaches  expr2 

.    for  x  from  exprl   to  expr2  by  expr3    .  .  .    incremented  by  exprS 

on  each  iteration 

.    for  x  being  path    .  .  .        user  definable  iteration  paths 


When  there  are  multiple  for  clauses,  the  variable  assignments  occur  sequentially  by 
default  (parallel  assignment  may  be  specified),  so  one  for  clause  may  make  use  of 
variables  bound  in  previous  ones: 

(loop  for   i  below    10  i  starts  at  0  when  from  isn't  specified 

for   j    =    ( *    i   i )    .  .  .  ) 

The  with  clause  allows  you  to  establish  temporary  local  variable  bindings,  much  like 
the  let  special  form.   It's  used  like  this: 

( loop  with  f  oo  =  expr     expr  is  evaluated  only  once,  upon  entering  the  loop 
...    ) 

A  number  of  clauses  have  the  effect  of  accumulating  some  sort  of  return  value. 
The  form 

(loop  for  item  in  some-list 
collect  ( f oo  item)) 

applies  foo  to  each  element  of  some-list,  and  returns  a  list  of  all  the  results,  just  like 
(mapcar  #'foo  some-list).  The  keywords  nconc  and  append  are  similar,  but 
the  results  are  nconc-ed  or  appended  together.  Keywords  for  accumulating  numeri- 
cal results  are  count,  sum,  maximize,  and  minimize.  All  of  these  clauses  may  option- 
ally specify  a  variable  into  which  the  values  should  be  accumulated,  so  that  it  may 
be  referenced.   For  instance, 


70  FLOW  OF  CONTROL  Chapter  4 


(loop  for  x  in  list-of-frobs 

count  t   into  count-var  "t"  means  always  count 

sum  x  into  sum-var 

finally  (return  (//  sum-var  count-var))) 


computes  the  average  of  the  entries  in  the  list. 


The  while  and  until  clauses  specify  explicit  end-tests  for  terminating  the  loop 
(beyond  those  which  may  be  implicit  in  for  clauses).  Either  is  followed  by  an  arbi- 
trary expression  which  is  evaluated  on  each  iteration.  The  loop  is  exited  immedi- 
ately if  the  expression  returns  the  appropriate  value  (nil  for  while,  non-nil  for  until). 

(loop  for  char  =  (send  standard- input  :tyi) 
until  (char-equal  char  #\end) 
do  (process-char  char)) 

The  when  and  unless  clauses  conditionalize  the  execution  of  the  following  clause, 
which  will  often  be  a  do  clause  or  one  of  the  value  accumulating  clauses.  Multiple 
clauses  may  be  conditionalized  together  with  the  and  keyword,  and  if -then-else 
constructs  may  be  created  with  the  else  keyword. 

( loop  for  i  from  a  to  b 
when  (oddp  i) 

collect  i  into  odd-numbers  and  do  (print  i) 
else  collect  i  into  even-numbers) 

The  return  clause  causes  immediate  termination  of  the  loop,  with  a  return  value  as 
specified: 

(loop  for  char  =  (send  standard- input  :tyi) 
when  (char-equal  char  #\end) 

return  "end  of  input" 
do  (process-char  char)) 

Please  refer  to  the  documentation  for  a  more  complete  discussion  of  loop  features. 
Of  particular  importance  are  prologue  and  epilogue  code  (the  initially  and  finally 
keywords),  the  distinction  between  ways  of  terminating  the  loop  which  execute  the 
epilogue  code  and  those  which  skip  it,  aggregated  boolean  tests  (the  always,  never, 
and  thereis  keywords),  the  destructuring  facility,  and  iteration  paths  (user-definable 
iteration-driving  clauses) . 


Section  4.4  Iteration  71 


4.5  A  Bit  More  on  Working  with  Macros 

Since  so  many  of  the  control  structure  constructs  are  macros,  you'll  probably  find  it 
helpful  in  working  with  them  to  be  able  to  see  what  forms  they  macroexpand  into. 
The  most  basic  of  the  tools  for  expanding  macros  is  the  macroexpand  function.  It 
takes  a  list  as  an  argument  and  returns  its  expanded  version: 

(macroexpand  '(if  (test)  (do-this)  (do-that)))) 
-»  (COND  ((TEST)  (DO-THIS))  (T  (DO-THAT))) 

The  grind-top-level  function,  for  pretty-printing,  is  also  useful  in  conjunction  with 
macroexpand. 

Rather  than  type  (grind-top-level  (macroexpand  ...  )  )  repeatedly,  an 
easier  way  to  expand  forms  in  a  lisp  listener  is  with  mexp.  Evaluating  (mexp) 
puts  you  into  a  macro  reading  and  expanding  loop.  You  type  a  form,  and  it 
pretty-prints  the  expansion  and  waits  for  another  input  form.  Exit  by  pressing  the 
End  key. 

But  by  far  the  easiest  way  to  see  what  something  expands  into  is  the  c-sh-M  com- 
mand in  the  editor.  When  you  place  the  cursor  at  the  beginning  of  a  lisp  expres- 
sion and  type  c-sh-M,  the  macro-expansion  of  the  form  is  shown  in  the  typeout  win- 
dow. If  you  give  c-sh-M  a  numeric  argument,  it  inserts  the  expanded  form  into  the 
buffer.  c-sh-M  only  expands  the  top-level  form,  not  any  of  its  subforms  which  are 
themselves  macros.   m-sh-M  expands  subforms  as  well. 

Of  course,  you  can  also  use  Meta-.  on  a  macro  to  edit  its  definition,  but  it's  often 
more  useful  to  see  what  a  macro  expands  into  than  to  see  how  it  does  it. 


4.6  Fun  and  Games 

From  The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  at 

TASTE  noun. 

Aesthetic  pleasance;  the  quality  in  programs  which  tends  to  be  inversely  pro- 
portional to  the  number  of  FEATURES,  HACKS,  CROCKS,  and  KLUGES 
programmed  into  it. 

OBSCURE  adjective. 

Little-known;  incomprehensible;  undocumented.  This  word  is  used,  in  an 
exaggeration     of    its     normal     meaning,     to     imply     a     total     lack     of 


72  FLOW  OF  CONTROL  Chapter  4 


comprehensibility.  "The  reason  for  that  last  CRASH  is  obscure."  "That 
program  has  a  very  obscure  command  syntax."  "This  KLUDGE  works  by 
taking  advantage  of  an  obscure  FEATURE  in  TECO."  The  phrase 
"moderately  obscure"  implies  that  it  could  be  figured  out  but  probably  isn't 
worth  the  trouble. 


Fun  and  Games  73 


4.7  Problem  Set  #4 

Questions 

1.  A.  Write  a  function  called  do-word  which  takes  one  required  argument,  a 
symbol,  and  two  optional  arguments,  both  fixnums.  If  the  symbol  is 
one  of  : point,  :  rectangle,  :  triangle,  or  :  circle,  the  func- 
tion should  draw  the  specified  kind  of  object  on  standard-output,  at  the 
coordinates  specified  by  the  fixnum  arguments  (choose  any  size  you  like 
for  the  figures).  If  the  symbol  is  : reverse,  the  function  should  tog- 
gle the  state  of  reverse-video-p  for  standard-output.  If  the  sym- 
bol is  :  erase,  the  function  should  clear  standard-output.  If  the  sym- 
bol is  anything  else,  it  should  call  the  function  beep. 

B.  Write  another  function,  called  read-chars,  which  reads  a  series  of  char- 
acters from  the  keyboard.  When  the  Return  key  is  pressed,  it  makes  a 
string  out  of  all  the  characters  read  (before  Return),  and  returns  a 
symbol  in  the  keyword  package  whose  print-name  is  that  string.  That 
is,  if  the  characters  "s,"  "a,"  "m,"  "p,"  "1,"  "e"  and  "<cr>"  were 
typed,  the  symbol  :  sample  would  be  generated.  (Normally,  you 
wouldn't  write  such  a  function  because  there  are  already  several  built- 
in  functions  which  do  the  same  sort  of  thing  and  with  more  features. 
But  for  the  sake  of  demonstrating  a  point  or  two...) 

C.  Write  a  third  function,  called  main-loop,  which  repeatedly  calls  read- 
chars  and  then  do-word  on  the  result.  It  should  provide  the  optional 
arguments  to  do-word,  and  increment  one  or  both  each  time  so  that  the 
figures  are  drawn  across  the  top  of  the  screen,  and  then  in  a  second 
row  below  the  first,  and  so  on,  with  each  position  200  pixels  from  the 
previous  one.  That  is,  if  standard-output  is  a  window  whose  dimensions 
are  1088  by  749,  the  optional  arguments  should  be  (0,0),  then  (200,0), 
(400,0),  (600,0),  (800,0),  (0,200),  (200,200)  ...  (400,800).  (Don't 
worry  about  resetting  the  coordinates  after  an  :  erase,  or  not  step- 
ping after  a  :  reverse  —  just  allow  blank  spots.)  This  version  of 
main-loop  should  iterate  until  it  reaches  the  bottom  right  corner  of  the 
window.  You'll  probably  want  to  touch  up  do-word  so  that  it  draws 
the  figures  centered  in  the  200  x  200  area  whose  upper  left  corner  it  is 
given. 

D.  Alter  main-loop  and  (read-chars)  so  that  if  at  any  point  you  press  the 
End  key,  even  in  the  middle  of  typing  a  word,  main-loop  will  return 
immediately. 

E.  Make  similar  alterations  so  that  the  Line  key  will  have  the  effect  of 


74  FLOW  OF  CONTROL  Chapter  4 


skipping  any  remaining  positions  in  the  current  row  and  continuing  at 
the  beginning  of  the  next  row. 

2.  Write  three  functions  which  meet  the  following  spec,  one  using  a  mapping 
operator,  one  using  do,  and  one  using  loop:  f  takes  one  argument,  a  list  of 
fixnums,  and  returns  a  list  containing  only  the  even  numbers  from  its  argu- 
ment. That  is, 

(evens    '(12345))      -»      (2   4) 

3.  Like  (2),  but  this  time  the  list  which  f  returns  includes  only  those  elements  of 
the  argument  which  are  less  than  the  succeeding  element.  That  is, 
(less-thans    '(36725435))      -      (3623) 

4.  Write  a  function  which  takes  two  arguments,  a  fixnum  "n"  and  a  list  "1," 
and  uses  a  mapping  operator  to  return  a  list  consisting  of  the  elements  of  1 
incremented  by  n.  Try  to  do  this  two  ways,  one  using  a  lambda  expression  as 
the  function  argument  to  the  mapping  operator,  and  one  just  using  # '  +. 

5.  Write  a  function  which  takes  one  argument,  a  fixnum  n,  and  returns  the  nth 
fibonacci  number,  subject  to  the  restriction  that  the  time  it  takes  should 
increase  linearly  with  n.   I  suggest  using  loop. 

6.  Write  a  function  of  no  arguments  which  finds  all  prime  numbers  between  2 
and  50000.  (You  might  find  it  easier  to  have  the  function  stop  at  the  first 
prime  greater  than  50000.)    I  suggest  using  loop  again. 

7.  The  function  mexp  only  expands  the  initial  operator  in  an  expression.  If  one 
of  the  arguments  to  that  operator  itself  uses  a  macro,  that  doesn't  get 
expanded.    That  is, 

(if  test    (do-this) 

(if  another-test  (do-that) 
(do-the-other) ) ) 

expands  into 

(COND    (TEST 

(DO-THIS) ) 
(T  (IF  ANOTHER-TEST  (DO-THAT)  (DO-THE-OTHER)))) 

instead  of 

(COND    (TEST 

(DO-THIS) ) 
(T  (COND  (ANOTHER-TEST 


Section  4.7  Problem  Set  #4  75 


(DO-THAT) ) 
(T    (DO-THE-OTHER) ) ) ) ) 

Write  mexp-all,  which  behaves  just  like  mexp  except  that  it  macroexpands 
subexpressions  and  thus  would  produce  the  second  of  the  expansions  shown 
above. 


76  FLOW  OF  CONTROL  Chapter  4 


Hints 


A.  The  body  of  do-word  should  consist  of  a  selectq  (or  a  defselect,  which 
is  a  macro  that  expands  into  a  selectq).  The  messages  you'll  need  to 
send  standard-output  are  :  draw-point,  :  draw-rectangle, 
: draw-triangle,  : draw-circle,  :reverse-video-p, 
:set-reverse-video-p,  and    : clear-window. 

B.  To  read  each  character,  send  :tyi  to  standard-input  or  terminal-io 
(usually  the  same  thing).  Collect  the  characters  into  a  list,  and  use 
string-append  to  combine  the  characters  into  a  string,  and  intern  to 
make  the  string  into  a  symbol.  Make  sure  the  characters  are  converted 
to  upper  case,  either  before  or  after  they're  collected  into  the  string. 

C.  The  :  inside-size  message  to  a  window  returns  two  values,  the 
width  and  height  of  the  interior,  in  pixels.  (The  difference  between 
inside-size  and  size  is  the  margin  area,  which  the  usual  output  mes- 
sages can't  draw  in.)  Use  these  (actually,  200  less  than  these)  as  the 
upper  bounds  on  your  iteration.  You  probably  want  two  nested  loops, 
an  outer  one  for  the  y  coordinate  and  an  inner  one  for  the  x  coordinate. 

D.  Wrap  the  body  of  main-loop  in  a  catch,  and  have  read-chars  do  a  throw 

at  the  appropriate  point. 

E.  Same  technique.   This  time  the  catch  goes  around  the  inner  loop. 

The  mapping  operator  should  be  mapcan.  The  do  would  need  a  structure 
very  much  like  that  produced  by  the  dolist  macro  (which  you  might  even 
want  to  use),  combined  with  some  parts  of  the  do  example  in  the  notes  which 
was  equivalent  to  maplist.  The  loop  would  use  collect,  conditionalized 
with   when. 

This  time  the  mapping  operator  should  be  mapcon.  The  do  and  loop  can  be 
done  in  any  of  several  ways.  There  could  be  one  iteration  variable  which 
took  on  the  value  of  successive  sublists,  and  then  you  could  take  its  first  and 
second  elements  and  do  the  comparison.  But  better  (because  it  requires 
fewer  redundant  cdr's  and  exits  more  cleanly)  would  be  to  have  the  value  of 
the  "first"  variable  be  directly  set  to  the  previous  value  of  the  "second"  vari- 
able. 

The  lambda  expression  adds  n  to  its  argument.  A  very  nice  way  to  do  this 
without  a  lambda  expression  is  to  use  a  circular  list.  (You  can  make  one 
yourself  with  rplacd,  but  the  circular-list  function  is  more  convenient.) 

Lots  of  choices  here.  You  probably  want  to  use  a  repeat  clause  to  control 
the  loop  termination.    But  the  tricky  part  is  that  you  need  to  have  a  value 


Section  4.7  Problem  Set  #4  77 


from  one  iteration  hang  around  through  the  next  one.  So  you  might  want 
something  like  the  loop  answer  to  (3),  where  one  variable  always  takes  on  the 
previous  value  of  another  one.  And  you'll  probably  want  to  use  a  finally 
clause  with  an  explicit  call  to  return. 

You  probably  want  a  subroutine  which  tests  whether  a  number  "n"  is  factor- 
able by  any  of  a  list  "1"  of  potential  factors.  The  loop  keyword  thereis 
may  be  helpful  in  writing  this  part.  Then  you'll  want  to  use  this  in  another 
loop  which  tests  each  number  from  2  up  for  factorability.  When  it  finds  a 
prime,  it  should  add  it  to  the  list  of  potential  factors. 

The  editor  commands  Macro  Expand  Expression  (c-sh-M)  and  Macro 
Expand  Expression  All  (m-sh-M)  display  exactly  the  same  difference  in 
behavior  we  wish  to  see  between  mexp  and  mexp-all.  So  you  should  be  able 
to  pull  some  code  out  of  Macro  Expand  Expression  All,  and  use  it  as  a  black 
box  to  help  you  create  mexp-all. 


78  FLOW  OF  CONTROL  Chapter  4 


Solutions 

A.  (defun  do-word  (message  ^optional  x  y) 
(selectq  message 

(: point  (send  standard-output  : draw-point  x  y) ) 
(: rectangle  (send  standard-output  : draw-rectangle 

100  100  x  y) ) 
(: triangle  (send  standard-output  : draw-triangle 

x  y  (+  x  100)  y  (+  x  50)  (-  y  87))) 
(: circle  (send  standard-output  : draw-circle  x  y  50)) 
(: reverse  (send  standard-output  : set-reverse-video-p 
(not  (send  standard-output 

:reverse-video-p) ) ) ) 
(: erase  (send  standard-output  : clear-window) ) 
(otherwise  (beep)))) 

B.  (defun  read-chars  () 

(loop  for  char  =  (send  terminal-io  :tyi) 
until  (char-equal  char  Areturn) 
collect  (char-upcase  char)  into  char-list 
finally  (return  (intern  (apply  #' string-append 

char-list) 
"keyword" ) ) ) ) 

C.  (defun  main-loop  ( ) 

(multiple-value-bind  (width  height) 

(send  standard-output  : inside-size ) 
(loop  for  y  below  (-  height  200)  by  200 

do  (loop  for  x  below  (-  width  200)  by  200 
do  (do-word  (read-chars)  x  y) ) ) ) ) 

and  in  do-word 

(: point  (send  standard-output  : draw-point 

(+  x  100)  (+  y  100))) 
(: rectangle  (send  standard-output  : draw-rectangle 

100  100  (+  x  50)  (+  y  50))) 
(: triangle  (send  standard-output  : draw- triangle 

(+  x  100)  (+  y  57)  (+  x  50)  (+  y  143) 
(+  x  150)  (+  y  143))) 
(: circle  (send  standard-output  : draw-circle 
(+  x  100)  (+  y  100)  50)) 


Section  4.7  Problem  Set  #4  79 


D.  (defun  main-loop  ( ) 

(catch  'end-key 

(multiple-value-bind  (width  height) 

(send  standard-output  : inside-size ) 
(loop  for  y  below  (-  height  200)  by  200 

do  (loop  for  x  below  (-  width  200)  by  200 

do  (do-word  (read-chars)  x  y) ) ) ) ) ) 

(defun  read-chars  (  ) 

(loop  for  char  =  (send  terminal -io  :tyi) 
until  (char-equal  char  Areturn) 
when  (char-equal  char  #\end) 

do  (throw  'end-key  nil) 
collect  (char-upcase  char)  into  char-list 
finally  (return  (intern  (apply  #' string-append 

char-list) 
"keyword" ) ) ) ) 

E.  (defun  main- loop  ( ) 

(catch  'end-key 

(multiple-value-bind  (width  height) 

(send  standard-output  : inside-size ) 
(loop  for  y  below  (-  height  200)  by  200 
do  (catch  'line-key 

(loop  for  x  below  (-  width  200)  by  200 
do  (do-word  (read-chars) 
x  y))))))) 

(defun  read-chars  (  ) 

(loop  for  char  =  (send  terminal -io  :tyi) 
until  (char-equal  char  Areturn) 
when  (char-equal  char  #\end) 

do  (throw  'end-key  nil) 
when  (char-equal  char  #\line) 

do  (throw  'line-key  nil) 
collect  (char-upcase  char)  into  char-list 
finally  (return  (intern  (apply  #' string-append 

char-list) 
"keyword")))) 


(defun  evens  (list) 

(mapcan  #' (lambda  (n)  (and  (evenp  n)  (list  n)))  list)) 


80  FLOW  OF  CONTROL  Chapter  4 


(defun  evens  (list) 

(do  ((sublist  list  (cdr  sublist)) 
( item) 

(evens -found) ) 
( (null  sublist) 
(nreverse  evens-found) ) 
( setq  item  (car  sublist)) 
(if  (evenp  item)  (push  item  evens-found)))) 

(defun  evens  (list) 
(let  (evens-found) 
(dolist  (item  list) 

(if  (evenp  item)  (push  item  evens-found))) 
(nreverse  evens - f ound) ) ) 

(defun  evens  (list) 

(loop  for  item  in  list 

when  (evenp  item)  collect  item)) 

3.  (defun  less-thans  (list) 

(mapcon  #' (lambda  (1) 

( and    (  cdr    1 )  to  avoid  doing  (<  n  nil)  at  the  end 

(<    (first   1)    (second   1) ) 
(list    (first    1))) ) 
list)) 

(defun  less-thans  (list) 

(do  ((sublist  list  (cdr  sublist)) 
(item)  (good-ones)) 
( (=  1  (length  sublist) ) 
(nreverse  good-ones)) 
(setq  item  (car  sublist)) 
(if  (<  item  (second  sublist)) 
(push  item  good-ones)))) 

(defun  less-thans  (list) 

(loop  for  a  =  (car  list)  then  b 
for  b  in  (cdr  list) 
when  (<  a  b)  collect  a)) 

4.  (defun  add-to-list  (n  list) 

(mapcar  #' (lambda  (elt)  (+  elt  n) )  list)) 


Section  4.7  Problem  Set  #4  81 


(defun  add-to-list  (n  list) 

(mapcar  #'  +  (circular-list  n)  list)) 

5.  I've  fudged  the  repeat  counts  of  these  three  so  that  they'll  agree  on  which  is 
the  nth  fibonacci  number. 

(defun  linear-fib  (n) 
( loop  repeat  n 

for  a  =  0  then  b 
for  b  =  1  then  partial-sum 
for  partial-sum  =  (+  a  b) 
finally  (return  partial-sum))) 

(defun  linear-fib  (n) 
( loop  repeat  ( +  n  2 ) 

for  a  =  0  then  b 
for  b  =  1  then  partial-sum 
sum  a  into  partial-sum 
finally  (return  partial-sum))) 

(defun  linear-fib  (n) 
(loop  repeat  (1+  n) 
with  a  =  1 
sum  (progl  a  ( setq  a  partial-sum)) 

into  partial-sum 
finally  (return  partial-sum))) 

6.  This  takes  about  10  seconds  to  find  all  primes  up  to  50021  ("5100  of  them). 

(defsubst  factorable?  (n  factors) 
( loop  for  f  in  factors 

while  (<  (*  f  f)  n) 

thereis  (zerop  (remainder  n  f)))) 

(defun  primes  ( ) 
(loop  for  n  from  2 

unless  (factorable?  n  found) 
collect  n  into  found 
and  when  (>  n  50000)  return  (length  found)))) 

7.  The  editor  command  Meta-X  Macro  Expand  Expression  All  calls  a  function 
named  macro-expand-all  to  do  the  actual  expansion.  It's  kind  of  messy,  but 
it  basically  does  a  recursive  tree  walk  of  the  input  form,  expanding  each  part. 
Understanding  how  it  works,  however,  is  not  really  necessary.   All  we  need  to 


82  FLOW  OF  CONTROL  Chapter  4 


know  is  what  it  does;  we  can  treat  it  as  a  black  box.  Here  is  the  original 
definition  of  mexp,  and  one  for  mexp-all,  which  modifies  mexp  to  use  macro- 
expand -all. 

( DEFUN  MEXP  ( ) 

(LOOP  WITH  (FORM  FLAG) 

DOING  (FORMAT  T  "~2L") 

(MULTIPLE -VALUE  (FORM  FLAG) 

( PROMPT-AND-READ  ' : EXPRESSION-OR-END 
"Macro  form  -♦  "  )  ) 
UNTIL  (EQ  FLAG  ':END) 
DO  (LOOP  AS  NFORM  =  FORM 

DO  (SETQ  FORM  (MACROEXPAND- 1  NFORM)) 
UNTIL  (EQ  FORM  NFORM) 
DO  (PRINC  "  -»  ") 

(GRIND-TOP-LEVEL  FORM)))) 

(DEFUN  MEXP-all  ( ) 

(LOOP  WITH  (FORM  FLAG) 

DOING  (FORMAT  T  "~2&") 

(MULTIPLE -VALUE  (FORM  FLAG) 

(PROMPT-AND-READ  ' : EXPRESSION-OR-END 
"Macro  form  -»  "  )  ) 
UNTIL  ( EQ  FLAG  ' : END ) 
DO  (PRINC  "  ■+  ") 

(GRIND-TOP-LEVEL  ( zwei : macro-expand-all  FORM)))) 


Chapter  5 

THE  GRAPH  EXAMPLE 


This  chapter,  rather  than  present  some  abstracted  features  of  the  lisp  language  or 
of  the  lisp  machine  operating  environment,  will  cover  a  programming  example 
which  puts  to  use  many  of  the  features  we  have  previously  discussed.  The  piece  of 
code  in  question  allows  one  to  display  and  manipulate  simple  undirected  graphs, 
that  is  sets  of  nodes  connected  by  arcs. 

If  your  site  has  loaded  the  tape  which  accompanies  this  book,  you  can  load  the  code 
by  using  the  CP  command  Load  System  graph  [or  evaluating  (make- 
system  'graph)].  Once  the  code  has  been  read,  start  the  program  by  evaluat- 
ing   (send    (tv: make -window    'graph-frame)    : select). 

Please  refer  to  section  5.5,  which  contains  a  picture  of  the  program  in  operation 
and  a  listing  of  the  code.  The  first  three  sections  will  point  out  and  briefly  discuss 
the  interesting  features  of  the  code.  The  basic  mechanism  is  contained  in  the  first 
half  of  the  file.  All  the  graph  manipulation  functionality  is  there,  provided  you're 
willing  to  type  in  awkward  forms  to  a  lisp  listener.  The  rest  of  the  file  provides  a 
more  convenient  user  interface. 


84  THE  GRAPH  EXAMPLE  Chapter  5 


5.1  The  Nodes  and  Arcs 

The  four  defvar's 

These  four  declarations  are  for  global  variables  that  will  be  needed  at  various 
places  throughout  the  code.  A  defvar  must  precede  the  first  appearance  of  the  vari- 
able so  that  the  compiler  knows  the  symbol  refers  to  a  special  variable.  Another 
good  reason  for  putting  them  at  the  beginning  is  so  anyone  reading  the  code  can 
quickly  find  out  what  hooks  are  available  for  modifying  the  program's  behavior. 

The  node  defflavor 

All  five  instance  variables  are  sellable  (you  may  recall  that  settable  implies  get- 
table  and  initable).  The  :  required- init-keywords  option  specifies  that 
every  call  to  make-instance  must  include  initial  values  for  xpos  and  ypos. 

defun-method 

This  facility  is  sort  of  a  cross  between  defun  and  defmethod.  It's  used  for  defining 
functions  to  be  called  from  inside  methods,  which  need  access  to  the  instance  vari- 
ables. For  defun-methods  to  be  compiled  optimally,  they  should  be  defined  before 
they  are  used. 

The    :  init  method 

The  last  thing  make-instance  always  does  is  call  the  flavor's  :  init  method,  if  it 
has  one.  Here  you  can  specify  operations  to  be  performed  on  every  instance  of  your 
flavor,  upon  being  instantiated.  I  use  this  one  to  set  the  radius  of  the  new  node 
according  to  the  size  of  its  label,  and  to  add  the  node  to  the  list  of  all  nodes.  Note 
that  many  of  the  window  mixins  already  have  :  init  methods,  so  if  your  flavor  is 
built  on  some  of  them  you'd  better  use  a  before  or  after  daemon  rather  than  a  pri- 
mary method  so  you  don't  override  the  other  one. 


ignore  as  an  argument 

Use  of    ignore  in  a  lambda-list  for  an  argument  which  isn't  going  to  be  used 
saves  you  from  getting  a  compiler  warning  about  an  unused  variable. 


: send-if-handles 

This  method  comes  with  si:vani!la-flavor.  The  specified  message  is  sent  only  if  the 
object  has  a  handler  for  it.  This  avoids  unclaimed  message  errors  in  cases  when 
you  can't  be  sure  of  the  exact  flavor  of  the  object  you're  dealing  with.    The 


Section  5.1  The  Nodes  and  Arcs  85 


:  primitive-item  message  has  to  do  with  mouse-sensitive  items.    We'll  get  to 
that  a  little  later. 


map-over-arcs 

I  wrote  this  macro  to  have  a  handy  way  to  iterate  over  all  the  arcs.  For  each  node 
it  runs  through  all  its  arcs.  If  it  has  already  seen  that  arc  it  goes  on.  If  it  hasn't,  it 
executes  the  body  forms  with  the  specified  variable  bound  to  the  arc,  and  marks  the 
arc  as  visited.  Note  the  use  of  gensym  to  make  sure  the  mark-var  and  node-var 
don't  shadow  any  variable  bindings. 


5.2  Managing  Multiple  Windows  and  Processes 

We  now  have  everything  needed  to  make  and  alter  graphs,  but  it  would  be  very 
awkward  to  do  it  by  typing  forms  like 

(make-instance  'arc 

model  (make-instance  'node  :xpos  135  :ypos  251) 
:node2  (make-instance  'node  :xpos  338  :ypos  92)) 


The  rest  of  the  file  is  concerned  with  making  it  easy  to  do  this  sort  of  thing.  First 
we  define  a  frame  (an  object  composed  of  several  windows).  Our  frame  has  two 
panes,  one  for  display  of  the  graph,  and  one  for  typing  lisp  forms.  Then  we  set  up 
a  process  in  the  graph  pane  which  just  watches  for  mouse  clicks  on  the  mouse- 
sensitive  items  (the  nodes)  and  dispatches  appropriately.  The  lisp  pane,  by  virtue 
of  being  built  on  tvtlisp-Iistener,  will  automatically  have  its  own  process  for  reading 
lisp  forms,  evaluating  them,  and  printing  the  results. 

Managing  multiple  processes  is  something  people  often  find  confusing,  at  least  the 
first  few  times.  Windows,  processes,  and  i/o  buffers  are  all  independent  objects  on 
the  lisp  machine,  so  you  can  have  nearly  any  number  of  each.  A  window  can  have 
zero  or  one  processes  running  in  it,  and  any  number  of  processes  can  exist  indepen- 
dently of  windows;  windows  can  each  have  their  own  i/o  buffers,  or  any  number  of 
them  can  share  a  single  i/o  buffer;  any  process  can  read  from  (or  stuff  characters 
into)  any  i/o  buffer.  How  do  you  decide  how  many  you  want?  I'm  not  sure  how 
generally  applicable  they  are,  but  here  are  some  guidelines  you  can  try  out. 

First  decide  on  the  windows:  the  number  of  windows  is  your  number  of  distinct 
output  channels  to  the  user,  so  you'll  need  as  many  as  you  have  things  you  want  to 
display   simultaneously.     In   this   example  we  want   to  see   the  graph   and   our 


86  THE  GRAPH  EXAMPLE  Chapter  5 


interaction  with  a  lisp  listener,  thus  we  have  two  windows. 

Next  think  about  your  input  channels  from  the  user.  You'll  probably  want  to  use 
one  i/o  buffer  for  each.  In  our  case  we  need  one  for  keyboard  typein  (lisp  forms) 
and  one  for  mouse  clicks  on  the  mouse-sensitive  items.  Hopefully  it  will  be  obvious 
how  the  i/o  buffers  and  windows  match  up.  For  this  example  it  is:  we'll  use  the  i/o 
buffer  of  the  window  displaying  the  graph  for  mouse  clicks,  and  the  i/o  buffer  of 
the  window  displaying  lisp  interaction  for  keyboard  typein.  (See  chapter  7  for  a 
situation  that  calls  for  having  two  windows  share  an  i/o  buffer  so  that  the  process 
running  in  one  can  see  input  from  both.) 

Now  processes.  For  each  i/o  buffer  there  will  have  to  be  a  process,  generally  one 
running  in  the  window  to  which  the  i/o  buffer  belongs.  (Having  several  processes 
read  from  a  single  i/o  buffer  would  lead  to  undesirable  "race  conditions,"  where  the 
program's  behavior  randomly*  depends  on  which  of  the  processes  happens  to  get  to 
a  particular  input  first.)  If  there  are  leftover  things  to  do  which  don't  involve  direct 
communication  with  the  user,  you  can  create  extra  processes  running  without  win- 
dows. 

In  deciding  how  many  i/o  buffers  and  processes  you  need,  keep  in  mind  that  some 
tasks  will  be  handled  by  the  mouse  process,  for  free.  Think  back  to  problem  set 
#2,  problem  4,  when  you  defined  a  : mouse-click  method  which  drew  a  square 
where  the  mouse  was  clicked.  That  window  didn't  have  a  process  in  it,  and  you 
made  no  use  of  its  i/o  buffer.  It  was  the  mouse  process  that  watched  for  user  input 
via  the  mouse  and  called  your  method  when  appropriate.  Similarly,  in  this  graph 
example,  we'll  define  a  : mouse-click  method  to  create  new  nodes  at  the  mouse 
position  (see  below),  and  this  will  happen  independently  of  our  own  processes  and 
i/o  buffers.  The  mouse  process  does  it  all.  There  are  other  tasks,  however,  for 
which  the  mouse  process  only  does  some  of  the  work.  It  turns  out  that  handling 
clicks  on  mouse-sensitive  items  fall  into  this  category.  The  details  are  covered  later, 
but  what's  relevant  here  is  that  when  a  mouse-sensitive  item  is  clicked  on,  the 
mouse  process  simply  stuffs  something  into  the  i/o  buffer  of  the  window  under  the 
mouse,  and  does  no  more.  Somebody  else  has  to  notice  what's  in  the  i/o  buffer  and 
do  something  about  it.    That's  why  the  window  displaying  the  graph  needs  a  pro- 


See  hacker's  definition  at  end  of  chapter. 


Section  5.2  Managing  Multiple  Windows  and  Processes  87 


5.3  The  Windows  and  the  Mouse 

The  graph-frame  defflavor 

This  defflavor  uses  the  :def ault-init-plist  option,  which  lists  alternating 
keywords  and  values.  The  effect  is  as  though  the  keywords  and  values  were  present 
in  every  make-instance  for  this  flavor  (unless  explicitly  overridden).  The 
:  selected-pane  init  keyword  means  that  whenever  the  graph  frame  receives  a 
:  select  message,  it  will  pass  it  on  to  the  the  lisp  pane.  The  :  panes  keyword 
says  that  this  frame  has  two  panes,  named  "graph"  and  "lisp,"  and  that  they  are 
instances  of  the  flavors  graph-pane  and  tv:lisp-listener-pane,  respectively.  The 
:  configurations  keyword  specifies  the  layout  of  the  frame.  Configuration 
specs  are  often  very  messy,  and  you  should  try  to  read  up  about  them.  This  simple 
spec  states  that  the  graph  and  lisp  panes  are  stacked  vertically,  with  the  graph  pane 
occupying  the  top  60%  of  the  frame's  area,  and  the  lisp  pane  occupying  the  rest. 


Selection 

The        next        two        methods,  :alias-for-selected-windows        and 

:  selectable-windows,  are  ones  which  applications  programmers  don't  usually 
mess  with.  Although  what  these  particular  methods  do  is  easy  to  see,  the  manner 
in  which  they  affect  the  behavior  of  the  Select  key  and  system  menus  is  extremely 
obscure.  The  only  reason  they're  here  is  because  I  thought  it  would  be  nice  if  we 
could  use  the  lisp  pane  to  make  our  frame  accessible  via  Select  L.  Take  a  look  at 
the  comments  in  the  code,  and  don't  worry  about  it  too  much  if  you  don't  com- 
pletely understand.  (Incidentally,  the  bug  in  the  speech  editor  which  I  mentioned 
in  the  introduction  to  Part  II  of  the  second  problem  set  had  to  do  with  these  mes- 
sages.) 

The  graph-pane  defflavor 

This  flavor  is  based  on  graph-window  (defined  below),  with  tv:pane-no-mouse- 
select-mixin  added.  tv:pane-no-mouse-select-mixin  itself  is  just  a  combination  of  the 
flavors  tv:pane-mixin  and  tv:dont-select-with-mouse-mixin.  The  former  provides  the 
functionality  a  window  needs  to  be  a  part  of  a  frame.  The  latter  fixes  it  so  that  a 
pane  won't  show  up  in  various  system  menus.  Otherwise  those  menus  would  con- 
tain separate  entries  for  every  pane  in  every  frame,  which  is  most  inelegant.  All 
you  really  want  is  one  entry  for  each  frame.  (As  to  exactly  what  that  one  entry 
should  be,  see  the  previous  paragraph.) 

The  graph-window  defflavor 

This  is  the  definition  of  the  window  in  which  the  graphs  are  to  be  displayed.    It 


88  THE  GRAPH  EXAMPLE  Chapter  5 


includes  tv:process-mixin  so  that  there  will  be  a  process  running  in  the  window,  and 
tvtbasic-mouse-sensitive-items,  so  the  window  can  display  items  which  will  be  mouse 
sensitive.  We  use  :default-init-plist  again  here.  The  : process  key- 
word gives  the  name  of  a  function  which  will  be  called  on  one  argument  (the  win- 
dow) the  first  time  the  window  is  exposed.  Such  functions  are  typically  written  as 
loops  which  never  return.  The  :  item-type-alist  is  an  instance  variable  con- 
trolling the  behavior  of  the  mouse-sensitive  items.  The  contents  of  this  list  are 
described  below.  The  :blinker-p  keyword  specifies  that  this  window  is  to  have 
no  blinkers,  and  the  :  font-map  keyword  is  a  list  of  fonts  this  window  is  to  start 
out  knowing  about.  In  this  case,  the  window's  sole  font  will  be  Helvetica,  12  point 
italic.  (The  default  font  we're  all  so  familiar  with  is  called  "cptfont,"  so  the  font 
object  may  be  found  as  the  value  of  the  symbol   fonts  :  cptfont.) 

The    :  init  method  for  graph-window 

This  is  where  the  variable  *graph-window*  gets  set.  Note  that  this  setup  assumes 
there  is  only  one  active  graph-window  around  at  a  time.  Whenever  one  is  created 
the  old  binding  of  *graph-window*  is  lost,  and  anybody  trying  to  use  the  old  win- 
dow is  likely  to  get  confused.  (If  you  wished  to  have  several  graph-windows  around 
simultaneously,  you'd  have  to  think  of  something  more  clever  than  a  single  global 
variable  to  keep  track  of  them.  Similarly,  the  global  variable  *a!l-the-nodes*  would 
have  to  go  if  you  wanted  different  graphs  in  the  different  windows.)  Note  also  that 
this  is  an  after  daemon,  to  avoid  clobbering  the  important  :  init  method  defined 
for  tvrsheet. 

The  main-loop  for  graph-window's  process 

This  loop  simply  reads  blips  from  the  window's  i/o  buffer  and  dispatches.  The  only 
blips  it's  expecting  are  ones  with  a  first  element  of  :  typeout-execute.  These 
blips  are  generated  in  the  mouse  process  when  someone  clicks  on  a  mouse-sensitive 
item.  The  remainder  of  the  blip  will  be  a  function  name,  dependent  on  the  type  of 
item  and  type  of  click,  and  the  item  itself.  This  loop  simply  calls  the  function  with 
two  arguments,  the  item  and  the  graph-window.  As  we'll  soon  see,  the  items  will 
be  nodes,  and  the  functions  will  be  ones  like  delete-node,  rename-node.  etc.,  all 
defined  below. 

The    :  refresh  method 

This  generates  the  picture.  It  sends  each  node  and  each  arc  the  : draw- self 
message.  (Note  the  use  of  map-over-arcs.)  This  is  an  after  daemon  so  we  don't 
override  the    :  refresh  method  of  tv:sheet. 


Section  5.3  The  Windows  and  the  Mouse  89 


The    :who-line-documentation-string  method 

The  response  a  window  gives  to  this  message  is  the  string  which  is  displayed  in  the 
mouse  documentation  line  at  the  bottom  of  the  screen  whenever  the  mouse  is  over 
the  window.  :  override  is  a  kind  of  method  combination  we  haven't  discussed 
before.  It  is  similar  to  :  or  combination  in  that  if  it  returns  nil  other  methods  get 
a  chance  to  run  and  if  it  returns  anything  else  they  don't.  It's  different  from  :  or 
combination  in  that  some  of  the  remaining  methods  may  be  before  or  after  dae- 
mons, which  isn't  allowed  with  :or  combination.  In  this  case,  the  intent  is  that  if 
the  mouse  is  not  over  a  mouse-sensitive  item,  the  string  supplied  in  this  method 
should  be  displayed.  But  if  it  is  over  a  mouse-sensitive  item,  some  other  method  (in 
particular,  the  one  on  flavor  tv:basic-mouse-sensitive-items)  should  be  allowed  to 
specify  the  documentation  string. 

The    : mouse-click  method 

If  the  mouse  is  not  over  a  mouse-sensitive  item,  and  if  the  click  was  a  single  one  on 
the  left  button,  make  a  node  at  the  mouse  position  and  display  it.  Otherwise  let  the 
other  : mouse-click  methods  have  a  chance.  (Recall  that  : mouse-click 
methods  have    :or  type  combination.)    The  new  node  will  have  no  label. 

The  guts  of  the  mouse-sensitive  items 

For  each  type  of  mouse-sensitive  item  a  window  knows  about,  there  is  a  set  of  pos- 
sible operations.  (Graph-window  currently  knows  about  only  one  type  of  item,  the 
:node  type.)  The  item-type-alist  (recall  that  this  is  an  instance  variable  of 
tvrbasic -mouse-sensitive-items)  tells  what  the  possible  operations  are  for  each  type, 
and  also  indicates  that  one  of  them  is  the  default  operation.  The  : mouse-click 
method  for  tv:basic-mouse-sensitive-items  is  set  up  so  that  if  you  click  left  over  an 
item,  a  :  typeout-execute  blip  is  forced  into  the  window's  i/o  buffer,  listing 
the  default  operation  and  the  item  itself.  If  you  click  right,  it  pops  up  a  menu  with 
all  the  operations  for  that  type  of  item,  and  when  you  choose  one  a  :  typeout- 
execute  blip  is  sent  containing  the  chosen  operation  and  the  item.  It's  up  to  the 
process  running  in  the  window  to  read  these  blips  from  the  i/o  buffer  and  do  some- 
thing with  them.  As  we've  just  seen,  the  process  in  the  graph  window  calls  the 
operation  as  a  function,  with  arguments  of  the  item  and  the  window. 

The  internal  structure  of  the  alist  is  a  bit  of  a  mess,  and  it  usually  is  not  built  by 
hand.  Instead,  it  is  generally  constructed  with  the  macro  tv:add-typeout-item-type, 
which  is  called  once  for  each  operation  defined  for  an  item.  The  first  argument  is 
the  alist  to  be  modified,  the  second  is  the  type  of  item,  the  third  is  a  string  to  name 
the  operation  (this  appears  in  the  menu  you  get  from  clicking  right  while  over  an 
item)   and  the  fourth  is  the  symbol  which  actually  ends  up  in  the  blip  if  this 


90  THE  GRAPH  EXAMPLE  Chapter  5 


operation  is  chosen.  The  fifth  and  sixth  arguments  are  optional.  If  the  fifth  arg  is 
t,  the  operation  becomes  the  default  operation  for  this  type  of  item.  If  the  sixth 
arg  is  present,  it  is  a  documentation  string  to  appear  in  the  who  line  while  the 
mouse  is  over  this  option  in  the  click-right  menu. 

You  can  see  that  for  the  graph  window  the  default  operation  (which  you  get  if  you 
click  left  over  a  node)  is  the  function  mouse-new-arc.  If  you  click  right  you  get  a 
menu  listing  four  other  operations  in  addition  to  "New  Arc,"  for  deleting  an  arc, 
moving  a  node,  renaming  a  node  (new  label),  or  deleting  a  node. 

The  function  definitions  for  the  operations 

All  that  remains  are  the  definitions  of  the  five  functions  which  implement  these 
operations.  The  first  two  (mouse-new-arc  and  mouse-delete-arc)  use  a  function 
from  the  Edit  Screen  menu  to  choose  an  arbitrary  point  in  the  window,  then  see  if 
there's  a  node  under  that  point,  and  if  so,  act  accordingly.  The  delete-node  function 
is  very  simple.  The  rename-node  function  uses  a  built-in  function  named  tv:get- 
line-from-keyboard  which  pops  up  a  small  window  and  prompts  the  user  to  type  in 
a  line  of  text.  The  function  for  moving  a  node  uses  the  same  piece  of  Edit  Screen 
as  the  earlier  two. 


: item  and    : primitive-item 

The  only  thing  I  haven't  explained  is  how  the  window  knows  that  some  portion  of 
its  display  is  supposed  to  be  a  mouse-sensitive  item,  and  of  what  type.  The  :  item 
and  : primitive-item  messages  take  care  of  that.  If  you  look  back  at  the 
: draw-self  method  for  node,  you'll  see  the  : primitive-item  message  we 
glossed  over  before.  What  this  one  does  is  tell  the  window  that  there  is  an  item  of 
type  mode,  with  left,  top,  right  and  bottom  edges  as  given.  The  window  has  an 
instance  variable  which  is  a  list  of  all  the  current  mouse-sensitive  items.  The  effect 
of  the  : primitive-item  method  is  just  to  push  the  given  item  on  the  list.  The 
:  item  method  (which  isn't  used  by  graph-window)  is  an  alternative  to 
: primitive-item  for  mouse-sensitive  items  which  are  text.  The  method  will 
take  care  of  printing  the  item  and  figuring  out  its  edges.  With  graphical  objects 
like  our  nodes  it  can't  do  that,  so  we  display  them  ourselves,  calculate  the  edges, 
and  send  the  : primitive-item  message.  To  see  whether  there  is  anything  on 
the  list  at  a  given  position,  send  the  : mouse-sensitive-item  message  with 
args  of  the  x  and  y  coords.  If  there's  an  item  on  the  list  matching  those  coords, 
some  information  about  it  will  be  returned,  including  the  item  itself,  its  type,  and 
its  edges.  This  method  is  primarily  for  internal  use  by  the  : mouse-click  and 
:  mouse-moves  methods  of  tv:basic-mouse-sensitive-items,  so  the  window  knows  to 
highlight  the  appropriate  region  when  the  mouse  is  over  an  item,  and  what  to  do  if 
there's  a  mouse  click. 


Section  5.3  The  Windows  and  the  Mouse  91 


5.4  Fun  and  Games 

From  The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  al: 

RANDOM 

1.  adjective.  Unpredictable  (closest  to  mathematical  definition);  weird.  "The 
SYSTEM'S  been  behaving  pretty  randomly." 

2.  Assorted;  various;  undistinguished;  uninteresting.  "Who  was  at  the  confer- 
ence?"  "Just  a  bunch  of  random  business  types." 

3.  Frivolous;  unproductive;  undirected.   "He's  just  a  random  LOSER." 

4.  Incoherent  or  inelegant;  not  well  organized.  "The  program  has  a  random  set 
of  MISFEATURES."  "That's  a  random  name  for  that  function."  "Well,  all 
the  names  were  chosen  pretty  randomly." 

5.  Gratuitously  wrong;  poorly  done  and  for  no  good  apparent  reason.  "This 
subroutine  randomly  uses  six  registers  where  two  would  have  sufficed." 

6.  In  no  particular  order,  though  deterministic.  "The  I/O  channels  are  in  a 
pool,  and  when  a  file  is  opened  one  is  chosen  randomly." 

7.  noun.  A  random  hacker.  This  is  used  particularly  of  high  school  students 
who  soak  up  computer  time  and  generally  get  in  the  way.  The  term  "high 
school  random"  is  frequently  heard. 

8.  One  who  lives  at  Random  Hall  at  MIT. 

J.  RANDOM  is  often  prefixed  to  a  noun  to  make  a  "name"  out  of  it  (by 
analogy  to  common  names  such  as  "J.  Fred  Muggs").  It  means  roughly 
"some  particular"  or  "any  specific  one."  The  most  common  uses  are  "J. 
Random  Loser"  and  "J.  Random  Nerd."  Example:  "Should  J.  Random 
Loser  be  allowed  to  delete  system  files  without  warning?" 


5.5  The  Program 


92 


THE  GRAPH  EXAMPLE 


Chapter  5 


Section  5.5  The  Program  93 


a> 

-0 

0)    0) 

•0 

a> 

A  tj 

0 

!* 

id    0 

^» 

Pi 

id 

rH    C 

rH 

rH 

ft 

0    4H 

0) 
A    0) 

P 

CO 

Pi    0 

m  TJ 

0 

•H 

CO 

rH     0 

> 

T> 

A    U 

H 

Pi 

Id 

P    0) 

0) 

4H 

rH 

CO 

•H    P 

u 

X 

0    0) 

4-1 

•H 

>    0) 

5 

rl 

ITJ 

■H 
ft 

43 
43  -P 

4-1 

43 

CO   -H 

P 

0 

Id 

01     P 

tj  o) 

u 

■H 

tn  Pi 

CO 

P 

O    ft 

0 

0) 

a> 

Cn 

a 

> 

X 

rH    TJ 

CJ 

TJ 

ITJ 

CD 

0) 

fi 

a> 

4H    Pi 

rH 

n 

Pi     * 

id 

A 

0    id 

4H 

0 

0  id 

•p 

P 

a 

rH 

CO 

«-»   rH 

4H 

P     ft 

c 

.ci 

CO    0) 

0 

4H 

Pi     CO 

«-~ 

•H 

o 

•H 

rH    £1 
0)     Id 

to 

0 

0)   -H 
TJ   TJ 

CM 

^^ 

XJ 

X    rH 

ID 

P 

Pi 

^-> 

1 

0) 

* 

•H 

0 

<v 

0)    0> 

rH 

1 

> 

•H 

-P 

■H 

ft    Pi 

o> 

PS    0) 

(TJ 
P 

p 
C 

0) 

ft  A 
0> 
TJ    0 

0) 
A 
id 

o 

CJ 

•H     S 

CO 

o 

—  P 

rH 

*~ 

CO 

id 

8 

—  V 
0) 

rt 
•rl 

4H 

CO      - 

1 

•  • 

£ 

•a 

0)  J3 

0 

rH     CT> 

0> 

a 

4-1 

p: 

N 

4H 

0)    Pi 

CO 

id 

0 

•rl 

•rl    CO 

0 

CO 

X  -H 

Pi 

3 

P 

» 

CO   rH 

TJ 

•H     P. 

0) 

b> 

-p 

0) 

p 

P 

ftp 

rH 

CO 

01 

0)     X 

CO 

0 

CO 

1 

•  » 

•a 

•H 

.C 

J3   -H 

•H 

0 

Pi 

&> 

a 

0 
■p 

rH 

-P 

•P     ft 

rH 

0 

•rl     Id 

•H 

co 

o 

P 

o 

0) 

P 
•H 

P 
CO 

V 

TJ 

o» 

§ 

* 

•d 

S 

* 

0 

o 

4-1 

TJ 

fl 

0 

^x 

Pi 

& 

>, 

* 

CO 

* 

„ 

•H 

•  •> 

<« 

CO 

0 

CO 

ID 

1 

ft 

rH 

n 

R 

0 

N 

43  — 

CO 

a 

•rl 

•H 

•H 

ft  — 

H 

CO 

TJ 

«-» 

TJ 

CO 

id  — 

J 

■H 

tj 

O 

id 

rl 

CO 

w 

id 
rl 

P! 

P   * 

C^   CO 

•  • 

T- 

1 

a 

CD 

1 

•H 

*    Pi 

01 

•0 

0) 

CO 

T) 

ID 

tn 

•H 

* 

c 

*     «■» 

TJ 

0) 

X 

0 

TJ 

p 

TJ  TJ 

* 

CO   CO 

0 

<-i 

C 

0 

m 

Pi  id 

s 

c 

rH 

•rl 

rH 

3 

•H     * 

Pi 
1 

A 

id 

CO 

CO 

c 

1 

a 
i 

01    U 
CO      1 

•  •> 

0 

CI 

•H 

TJ    0) 

1 

■rl 

Tl 

PI 

1 

CD 

^   0) 

A 

•rl 

Pi 

(0    N 

rl 

p 

•rl 

TJ 

TJ 

en 

p 

* 

P  -H 

a 

id 

0 

T) 

s 

0  \    0 

•H 

id 

CO 

* 

1      CO 

•H 

> 

K 

id 

■H 

Pi  \  Pi 

rH 

0) 

0) 

s 

0)     1 

Pi  -» 

i 

rl 

c 

* 

(0 

P 

•d 

0 

T>    Pi 

•H  — » 

0) 

0) 

•H 

~s 

P 

O 

0 

•a 

0  -H 

*-* 

B   rH 

O  M 

P 

a 

+ 

01 

a 

a 

Pi    &> 

rH 

*    -H 

Pi 

1 

CD 

* 

*_- 

a 

N 

P 

i 

•H 

1        rl 

•rl 

Pi 

id 

p 

CO 

r-i 

•H 

(0 

0) 

> 

e  (0 

c 

CO 

p 

•H 

<D 

CD 

X 

Pi 

■C 

1 

3  e 

0) 

P>    rH 

CO 

PI 

rl 

X3 

id 

•H 

k 

CO 

■p 

43 

6    i 

■0 

CO 

•rl     0) 

a 

•H 

CO 

id 

a 

a 

id 

ca 

ft 

•H    0) 

0 

u 

CO 

CO   T)    A 

■H 

T) 

P) 

rH 

* 

P 

ft 

rH 

(0 

Pi  tj 

C 

P 

0 

0     Id     Id 

| 

T) 

0 

•H 

g. 

rH 

rl 

■H    0 

aJ 

ft 

ft    P.   rH 

0) 

<D 

* 

TJ 

4H 

Id 

0> 

e  p! 

rl 

X 

>i~  ~  - 

•  i-\ 

P 

P 

m 

•H 

CO 

1 

4J 

CO 

P 

* 

rl 

p 

rl      rl 

0 

> 

id 

~ 

■  A 

ITJ 
P 

•H 

0) 

e 
i 

u 

^ 

* 

•H 

ITJ 

Id 

•0   id 

rH 

P 

0) 

p 

1 

4-1 

> 
4H 

> 

4H 

>      > 

4H    4H 

4-1 
4-1 

0) 
CO 

P 

4H 

CD 
CO 

0) 

0) 

0)     0) 

0) 

ID 

1* 

1* 

•0 

■0 

TJ    -0 

n 

TJ 

94 


THE  GRAPH  EXAMPLE 


Chapter  5 


■rl 

+J 

"O 

45 

(0 

0> 

h 

■H 

CD 

P 

••» 

45 

G 

> 

1 

0 

0 

CD 

«w 

■0 

c 

C 
•H 

P 

•H 

rH 

a 

> 

•• 

0) 

u 

A 

S 

u 

ft 

0 

a 

id 

73 

-^ 

o 

P 
d> 

•H 

CO    to 

CD 

s 

3  3 

43 

0 

•H   -H 

P 

C 

-d 

C 

■d  -d 

<d  id 

a 

CO 

CD 

u  u 

•rl 

•rH 

(0 

"" 

Q> 

*^ 

to  to 
0    0 

P 

ft 

_» 

££ 

£» 

A 

1 

fc 

10 

P 

>> 

w 

1     + 

rH 

0 

4H 
•H 

CM 

CO 

»--  "^ 

(V 

rH 

£ 

EH 

r-\ 

ft 

^  -^ 

A 

•H 

CO 

CD 

CO     CO 

p 

A 
» 

0) 
rH 

i 

42 
03 

, 

•H   -H 

>4-l 

CO 

■ — • 

-d  -d 

0 

-d 

^ 

CD 

CO 

Oi 

^^ 

id  id 

u   u 

43 

p 

CD 

P 

E-< 

fJ 

C 

CO 

P 

<d 

P 

0 

Cfl 

■H 

•H 

3 

to  to 

0> 

0) 

U 

I 

C^ 

h 

0! 

P 
P 

•H 

■d 

aa 

(V 

o 

•H 

J 

P 

CO 

03 

X    X 

-»  rH 

-H 

w 

1 

rl 

V 

CO 

^^ 

.-» 

a 

w 

<-^ 

CO 

■d 

1    + 

P    CD 

i 

03 

> 

0 

CD 

CO 

O  A 

»-» 

CO 

<D 

.— - 

0 

ft 

M 

0 

*~. 

&* 

CD 

rH 

3 

P 

.-» 

Eh 

■d 

s 

CD 

ft 

<4H 

o 

■o 

CO 

CD 

•H 

P 

(J 

c 

P 

X 

t-i 

p 

•H     0 

o 

0) 

a 

■a 

CO 

XS 

W 

•H 

CO 

C 

CD 

.-^ 

id 

P 

c 

-0 

id 

<d 

CD 

b 

5 

0 

CD 

+ 

CO 

to 

U 

■P 

0 

^ 

rH 

p 

6 

m 

^^ 

^^ 

ft 

O 

— 

CD 

P 

*^ 

10    (J> 

c 

03 

o 

X 

rH 

CD 

03 

<l)     C 

* 

&» 

* 

P 

p 

*+H 

C 

i 

e 

^-~ 

^-« 

>, 

-^ 

■d 

■d 

O  "~ 

P   -rl 

s 

c 

^ 

rH 

CO 

CD 

CD 

rH 

g 

2 

03 

-^ 

4H 

CD 

03 

CO 

a 

O 

P   to 

cd   T> 

0 

•rl  ~ 

rH 

CD 

CO 

CO 

CD 

I 

CD 

E 

rH 

r-{ 

r-i 

s 

03 

a 

id   u 

~    P 

•d 

c  — 

-— 

Id   "O 

CD 

CO 

r 

P 

03 

CD 

O 

ft 

■H 

45 

O 

1    U 

O 

c 

P    *4H 

CO 

0 

P 

I 

P 

CD 

CO 

P 

CO 

■d 

i 

P 

CD     03 

*->•  o 

■H 

rn 

fd   rH 

rJ 

4H 

a 

P 

P 

rH 

CO 

U 

1 

•H 

•H 

<d 

4H 

a 

03 

> 

P   o 

» 

•H 

S    CD 

•H 

o 

1 

CD 

C 

CD 

p2 

P 

* 

O 

Tl 

P 

•H 

« 

0    O 

•h  id 

1 

C 

=     to 

■d 

CD 

P 

* 

•H 

45 

i 

CD 

CO 

03 

1 

1 

p 

■d 

a  p 

C 

^ 

43 

<d 

p 

A 

<4H 

* 

P 

03 

CD 

^ 

rl 

S 

CO  T3 

•H 

T) 

oi   id 

•H     10 

rH 

ft  :* 

p 

CO 

P 

<d 

0 

ftrH 

2 

CD 

T3 

03 

? 

a 

(5 

03 

p 

••   3 

(1) 

id 

IW 

•H 

1 

T! 

ft  H 

C 

a 

rl 

0 

CD 

CD 

<^ 

..   o* 

•H 

JQ 

P 

•H 

p 

rH 

rH 

C 

P 

1 

Eh 

03 

T3 

-d 

x 

CO 

> 

»-» 

rH 

<U   T3 

0) 

d>  P 

CD 

rH 

CD 

•H 

CD 

0 

>»    2 

u 

a 

CD 

c 

■H 

CD 

CO 

CD     CD 

■d    (0 

rH 

* 

0 

CO 

CD 

<d 

-0 

* 

T3 

m 

H 

C 

■d 

•H 

i 

P 

■d 

u 

-d  -d 

0    P 

c 

«D 

A 

* 

0 

1 

0 

•H 

Pi 

■H 

o 

0 

s 

s 

» 

•H 

0 

rl 

0    — 

G 

-P 

P 

P 

P 

c 

A 

C 

CD 

45 

Cu 

P 

C 

c 

0 

0 

a 

(5 

03 

C 

*-  <u 

o 

0 

> 

4H 

ft 

e 

CO 

ft 

■H 

T3 

rH 

T3 

T3 

•H 

—    CO 

A 

c 

Pi- 

p 

0 

rH 

05 

0) 

03 

H 

u 

P, 

CD 

fi 

C 

P 

CJ 

O 

•g^ 

P 

p 

CD 

■d 

P 

•0 

c 

rH 

W 

ft 

X) 

•H 

J3 

CD 

H 

ft 

>d 

U 

T3    P 

CO 

0 

tn 

0 

CO 

0 

S 

03 

CO 

£ 

0 

03 

0  id 

A  -p 

Tl 

43 

45 

^ 

45 

rH 

■~^ 

45 

45 

-P    tt)  -0 

TJ   A 

p 

P 

4H 

p 

■d 

T3 

P 

45 

p  tr 

0)    CO 

c 

<d 

CO 

CD 

13 

CD 

p 

•H 

CD 

c  -d 

C 

CD 

CO 

Q)   +J 

B 

0 

3 

e 

£5 

6 

CD 

^ 

e 

CD 

C 

CD 

e 

El 

a  oi 

<w  •► 

o 

.- 

a 

MH 

03 

14H 

r-i 

14H 

CO 

01 

CO 

4H 

ft 

MH     CO 

0)    .- 

CD 

(1) 

CD 

CD 

0)  ^ 

■0 

T) 

T) 

T3 

13 

■d 

Section  5.5 


The  Program 


95 


•H    P 

a  a) 

(V 

—  .c 
v  m 
p  •• 

0)    > 

rH    P 

a) 

■?.§ 

M 

•d 
o  -d 

£§! 
o 
■d  u 
o  n 
.£  o 
p  .Q 

0)  «^ 

e 

4-1  •♦ 
0)  .- 
T3 


a>  in 

>  ~  a; 
0)  to  *d 
M  ~  O  --' 
ft    CO  u 

O  (0    * 

O   fc  o 

**  «3.g 

^  J  u  o 

(0  J  —  c 

>  p  I 

Z  P    a) 
w  ~  Z  .£ 

•H  W    P 

,C    J  W     I 

Eh  H 

o  cu  a* 

q  o  -P 

o  a> 


0)    <D 

■d  -d 
o  o 


fc  TJ  -d 

moo 
e  c  c 


S-l     V4 

fl    Hi 

O  ~ 

> 

id 


a>  a) 
•d  -d 
o  o 


0)  OJ  0) 

H   rH  rH  rH 

■H    .Q  jQ  £1 

C     <TJ  it}  rtj 

-p  +J  p 

P  -H  P 

Q)  (5  0) 

Ill-ri  (Jl 


96 


THE  GRAPH  EXAMPLE 


Chapter  5 


^ 

^ 

CO   -H 

^-^ 

^ 

P)  tn 

ft 

^ 

•H    £3 

CO 

J3  -H 

•H 

c 

■P  "0 

rH 

0) 

> 

■H 

3    P 

.C 

0) 

0    U 

ft 

C    CO 

<fl 

> 

P 

ft 

>»  0 

tnvo 

CO 

CO 

•H 

>!    CO 

§ 

o 

rH 

p 
■p  id 

3 

£ 

o 

rH 

ft 

C 

CO    CO 

0 

id 

0) 

-H     > 

■>-» 

O 

rl 

^1 

CO 

tn  -P 

w  -o 

p 

»■» 

o 

$ 

»»» 

—~ 

c 

co  A 

> 

1 

P 

0) 

c 

•H 

JCJ   -M  — 

■P    CO      • 

<-»  M 

id 

*-» 

c 

l 

e  4h 

CO    P 

> 

CN 

m 

CO          rH 

Sg 

i 

CO 

ft 

CQ    CO    CO 

« 

0 

i 

P 

3  .C   to  — 

(0      •> 

p 

& 

p 
cu 

C! 

CO 
0) 

Id  en  -P  — 
O  >-  -H 

-— 

e^ 

c 

*   N 

Q)                  -» 

P   * 

CM 

0> 

id  -h 

A           CO    CO 

(0    u 

CO 

p 

rH 

CO 

•  e  3 

^ 

M 

a 

, — i 

0) 

CO 

-  co   id   0 

p 

--^ 

C 

■H 

>— 

— 

J    S   P  -0 

Q>     .. 

? 

X 

« 

rH 

i  id  <m  a 

*-. 

■0 

-^ 

-^ 

ft 

1 

c 

•P     P      1     -H 

* 

0  u 

CN 

►, 

^ 

1 

ft 

•H 

O    4H   A     > 

I 

G    <d 

-p 

P 

-a 

^ 

CO 

<fl 

CO      1      ft    1 

*      -  > 

a> 

'— 

-~- 

.— » 

^~ 

& 

ft 

■H 

e 

rH    J3     Id   TJ 

to         1 

co 

>. 

CO 

* 

rH 

CO     ft   P     CO 

CO  TJ    O 

CO 

-o 

A 

A 

*S 

X! 

-— 

■H 

P 

^.^ 

co  id  tn  -P 

* 

•o  a  u 
o  oi  (« 

0 

P 

P 

P 

+J 

(D 

rH 

tn 

> 

«. 

P         u 

p 

ft 

* 

tn 

tn 

tn 

0> 

e 

* 

P 

id   tn  co  co 

a  co    - 

03 

a 

c 

C 

C 

nj 

A 

CO 

•H           JC    rH 

ja 

i  ^ 

> 

OJ 

0) 

cu 

CO 

n 

CU 

ft 

ft 

C 

>  id  -p  co 

CO          T3 

1 

rH 

rH 

rH 

rH 

4H 

C 

rtJ 

CO 

0 

CO 

~       R 

5  a  c 

o 

CO 

s 

| 

(0 

P 

■H 

•H 

CO    4H    (3     1 

■P  -H    CO 

M 

0 

-P 

ft 

tn  rH 

P 

rH     0     P     P 

P                 CO 

1            CO 

a) 

ft 

T— 

T— 

<N 

CN 

c 

1 

^^ 

^— 

rfl 

43         3    0 

to          a 

rH    P  ~ 

X 

3 

M 

P 

P 

U 

•H 

TJ 

P 

•H   -O   -P   4H 

>                V 

rH     Id 

>, 

m 

0) 

% 

g. 

to  id  co    i 

1                tn 

m    >    O"0 

t— 

3 

>> 

3 

>. 

p 

P 

CO    CO    P    CO 

o             •— 

*     1     CO 

0 

C 

u 

* 

13 

■o 

p 

U 

CO 

•H 

co  p»       «d 

p        "» 

o  *- 

a 

9 

^-* 

—^ 

-^ 

CO 

d) 

<D 

4H 

O     tO   -0   -H 

03  - — -  —    It 

G    P 

© 

co 

T— 

T— 

* 

* 

* 

* 

C 

rH 

c 

c 

O    CHH 

•H    Id    CO 

CO 

CO 

CO 

+ 

0 

0) 

rfl 

0 

id  -h   3   id 

"*    &  £.  * 

«   CO 
P           CO 

0 

CO 

a 

— ' 

N, 

N. 

s 

\ 

3 

o 

CO 

a 

u 

0    •• 

CO    (0    CO    > 

id  M  h 

■d 

0 

X 

p 

V 

\ 

s 

\ 

T3 

e  co      co 

U    C    C     I 

>   0   c 

I    4-i    3 

c 

p 

0) 

<1) 

P 

id  C  TJ  6 

P     0)    0>   X 

1 

CN 

(N 

V 

6 

P 

CO 

p  co  c  id 

id    tn  tn  P 

CO 

4-1 

to 

CO 

CO 

r— 

T— 

CN 

CN 

s 

CU 

•H 

4H   -P    Id    P 

rl~~§ 

-0    ft 

0 

0 

■H 

CO 

CO 

CO 

to 

u 

T3 

rH 

0)          4-1  — 

0    0 

1 

ft 

«— 

a 

0 

0 

0 

<u 

P 

a 

P   -H    CO     1      CO 

11    h    VI     • 

£5    0 

CO 

X 

s 

ft 

a 

i 

a 

0  r-t  e  xi  g 

>    id    id 

-  rH 

CO 

,C 

X 

X 

A 

-p 

0    i    id  ft  id 

O    >    >  A 

- 

tn 

I 

1 

•P 

ft 

•H 

ft  P  id  ft 

1     1     I    +3 

u 

-0 

tn 

+ 

+ 

id 

> 

c 

tO     tO    4H     P      1 

ft  *  <u  -h 

0    0 

CO 

C 

^ 

^ 

^ 

w 

u 

p 

■H 

co  -h    i    tn  "0 

A  p  tj  s 

SISa 

4-1  >0 

1 

4 

>1 

CD 

Cn 

1 

XH    O-   4) 

TJ 

T3 

rH 

CO 

P 

Id           -rl            -P 

Pi 

• — ■ 

a> 

M 

rH 

B   id   to  no   o 

o  «-  —  0 

•H 

3 

0 

3 

id   0  co 

P  —         0 

4-1 

rH 

> 

<fl 

tO     tO    XX    A    rH 

O                  rH 

* 

(fl 

(0 

4-< 

•H  <■             +J    CO 

IS    r 

S 

+j 

> 

rH 

CO 

a  v  a  co  to 

<u 

4H 

T3 

£-1    -rl     0     S     •• 

4H   H 

4-1 

rH 

4-1 

4H     > 

(U  — 

CO 

CO 

•-   •'   •*   CO   -P 

•0 

•o 

•o 

n 

Section  5.5  The  Program  97 


ft 
o 
p 

TJ    0) 
+»  <M    0)    > 

(OOP 

CO   TJ 
CD    P   -H     O 

(0  -H  +J 

AH    «    « 

c  s 
ft  «  s 

m^  ft  (I 

•HP  43 

rH  ft  £< 

CD  CO   ^ 

CD   ^  -H 

43     0J  rH 
P     6 

0)    4J 

CD    CD  43  -H 

CO   M  -P  — 

03   -H  tO  «-«■ 

h  mi  — 

>>      >  x  v 

CD     CO     <0   -H  C 

>!    &>43  >M  <0 

C  ft 

P  -H  Tj  CO  I 

O  43  rH  -rl  TJ 

CD  P  C  43  CD                                                            U 

H  O  tn  P 

a;  co  £  u 

CO    0)  CD  4-1     it! 

O    P      •  rH  II 

CD   TJ    H   —  CD  —  HO) 

43  a»  co  —  a>  ft 

p  43      e         ••         *  >  £ 

O      •    10  >  O  0)   P  <— 

c;  'H  h  ^  +j  nj.  i — i    i  4» 

>!  43    C  «H  -  C  Ig  ri 

<tj>a>i  -h  ft  cd  o  — 

S         6  43  —  *  OP        —  2  -H 

S          ft  C                I  +»  -H  —  &  >, 

O    Jl    g    fl  -O  43  II—  -H  —                    P 

+j   +j    CD    P  --  •*  ft  J43-H  >  I 

COP&lp  (0  OftCNP  O  r^ 

-O    >n  co  —  o  P  tjifl'-co  ■d  C 

•rl    CO    >>   CD  —    CO    CD  t?  C    P  rH  CD  «3  <0 

>C  CO    43       •>    rH  CO  -rl     fr  43  P  -rl 

>p?ocd  i3  e>*--us  > 

POCDOTJCO  -H  CD            I                    CO  -^  ^  ri   IH^ 

CO  TJ  43  P   -d  C  I  X  +J43+JP  -rl   rH    CD 

C     C  P  O     C  -H  P  -H  -H  ft    CO            C  —  C  C     CD    P 

•|-|  -rl  <M   -rl  >  O  6  I  (0   -rl   rH     O  P  O  CO     0   — 

S  <M  >      I  »4H  I  CD  P   rH   -H    4H  -rl  -H  —»0   — 

CD  O  111     I  91  I  P  >  &>  <0    C  >-  C  P  ft  T>    CD  — 

S     CD  O   rH  rH  CD  O  -H  •—     I            »  -H  O  O     C     X    4H 

43  C  C    <0  43  6  CD  P  *       CD    ft  ••  £3  OCDCDrH 

&HJ  O  O  -H  fl  fl  rH  -H                    ftlft  C  rHCOICD 

C  -rl  p  p  C  a,  CO  CO     >,    p     <0  P  4H  I     >-   P     CO 

•HM-tP-OCO"  co  C         copcdB         CD  i  (3         3   _ 

43     O     ft    C     CD     CD  I  CD  CD      I     ,!«!      I  -P   — •  rH  -HMOS 

■p        o  id  n  h  ai  cd  (3co        o   g   c  p       mh—       <d  <o        cdcd 


SrH 


CQCDC3  CO  -HI  O     CD   -rl     C  <0    4H  > 

p    p    <W    CD    CO    <0  S  *-»XCD  h+JrHO  ••  H  CD 


•e.-££.t 


4*1    <0    O   rH           ••    ft                 O  -'■H    «           ft  -H   43    4-1                  CD          rrift                 CDP 

<0    ft   CD    CD    C            I           ~    6  S    C           >C0           10           *   P    ••    ft 

CD          rH     CO    O    CD   TJ          «-     I  »     I      O  O                  ftOO'HO 

C    CD    CD   P           BCD                 O  O    CO    B  —  P  TJ*           Ori          T3          TJ 

CO    43     CO   -rl     CO     (0    P            CD     C  >0     CO      I      ?     CO  C     ?           PI              G     ft    5    rH 

+J                  -H     p     O            CI  C3CDOO-H  -HO             I      C           -HOSrH 

CD           CDP          *M    CD           03     (D  •HU-H'OrH  ?    T3            5    -H           >            0)     n3 

43    CO  43    O    C*    I    rH          ft  C  £    O    CO    C    ft                           IC          O    <0          1-0*0 

En    CD   P   <4H    C   43    CD           1(0  I     P    <fl  -rl     I  43  -ri          TJ    6          43*           C 

co         -Hftco      co,  43ft4a*p  ft>      a  •■      ftScrB 

C    P    CD   -d    «J    ••  ft   ••  ft H  <fl     I  -H  fl    CD    CD   <W 

•»wOO-HP>          rfl>  «>>>C  P43          >S          P  >J  ^  — 

>!CMHCP&)P            PP  U    *J    *J    *J    -r^  &>ft            10            C7>  — 

CQOOP^               tp^tji^  I  ^(0         43"O^CO 

id    O    10^   0)          TJ  P                                     pftC                 PCDTJ 

>>'OCP  P                    r-i  'O&i<0-HTJO43 

prHOCDOOCD         O  O                     C  O*          P»          Oiw? 

x      CD-OO43c0>  >                     id  43               tj>43 

C>C-HCDP^m  nJ                  *w  PC            -OPft 

OCD-H^PCD-rH  rH                           CD  CDPCCCDO 

QrH^plCB—          <W  IH                        T3  BCDSCDBO 

4-|x_,l4H  IW                           ••  IMCO^HCOM-lrH 

.-.».».»    .^    CD  '             CD  CD                      •-'  CD  — '          D  w          D   — 

.  ^    .  ^    .«-.«-.*-  rrj                  frl  irt  trj                  irj                  tr) 


98 


THE  GRAPH  EXAMPLE 


Chapter  5 


P 
■H 

o 
u 

0) 

to 

rH 
•H 

0) 

p 

e 

rH 
•H 

rH 
•H 

(3 

p 
a) 

o 

u 

c 

c 

CI) 

rH 

p 

0 

■d 

tt) 

03 

> 

0) 

0) 

o 

■d 

o 

-d 
o 

-d 

0 

13 

i  ■»■» 

0    B 

0) 

c 

(3 

c 

0) 

(0       • 

(3 

V 

1 

i 

> 

rj    rjj 

I 

43 

CD 

~~- 

d) 

0) 

o 

0    4) 

tt) 

rH 

» 

N 

0) 

p 

g 

e 

e  p 

to 

■H 

•H 

N 

0) 

tt> 

3 

C   ~ 

d> 

to 

•H 

rH 

c 

0) 

=      rH 

0 

13 

1 

(0 

0) 

0) 

to 

O    0) 

a 

~* 

•H 

c 

1 

■d 

p. 

3  ~ 

p  -d 

d>  i 

43 

•H 

c 

0  = 

< 

13   a> 

■P 

Cn 

•H 

e    • 

0 

o  ^ 

•H     10 

0 

p 

tJ> 

0) 

*-» 

0) 

--~ 

« 

4)  43 

r. 

P    3 

C 

03 

M 

p 

s 

S 

= 

=    d 

P 

P  o 

e 

03 

v 

03 

cu  o 

tt)    0 

o 

to   E 

0 

i 

e 

rH 

43 

(3 

0) 

>  C 

rH    P 

»  p 

i    •• 

•d 

■p 

i 

d) 

ft 

CU 

d 

0 

0 

tt)    03 

C    > 

4H 

ft 

o 

03 

Pi 

0 

S   to 

Q    O 

21 

O  P 

0) 

0 

P. 

c 

=      -rl 

=    u 

=      > 

■H 

rH 

p 

Cn 

43 

0) 

0 

9) 

P    X 

0) 

0) 

CO 

0)  jj 

0 

tt)    13 

u 

(0     1 

> 

> 

T3 

d) 

d 

•H 

d 

-d  c 

•d 

O 

P    tt) 

P 

p 

0  43 

0 

43 

0    P 

O    03 

O    03 

g> 

a  to 

--n 

-■* 

(3 

p 

c 

P 

c  0 

{3 

13 

0)     3 

= 

>»~ 

X 

>^ 

••   4H 

..  m 

..  m 

•H 

IS 

3 

4-1 

P. 

0 

0 

c 

X  P 

1 

i 

* 

0 

* 

0 

*  a 

* 

■P 

O    •• 

0) 

w 

_- 

P 

p 

4-1 

P    0 

p  p 

p  p 

CO 

0    > 

E 

to  X 

to 

p 

to 

tO   -H 

to  c 

to   fi 

0 

*d  P 

C 

to 

to 

•H 

3 

•H 

rH 

•H    P 

•H  -H 

•H  -H 

U 

1 

e 

O  S 

a 

o 

rH 

0 

rH 

CD 

rH   -H 

rH     O 

rH     O 

<4 

oj   e 

CD 

P  W 

ft 

03 

03 

42 

o)   to 

03     ft 

03     ft 

c   a> 

p 

P  E* 

X 

1 

0) 

1 

03 

1      O 

1 

•H    P 

(0 

3    H 

tt)  T3 

0) 

rH 

V     ft 

tt)  -d 

tt)  -d 

rH   -H 

:* 

43     I 

ft  0 

ft 

ft 

ft  (3 

&s 

45 

I       | 

en 

~  W 

cu 

>>  «3 

^ 

IS 

>^   > 

>,  tt) 

CO           -> 

o  a) 

> 

xs 

P 

P 

<1> 

P     tt) 

P 

+i 

0)        ~ 

43    > 

^  H 

0 

I 

to 

£3 

1    c 

1     0 

1   0 

u       <m 

>   -H 

-X   Eh 

c 

6 

•H 

e 

e 

e  c 

e  c 

«H           rH 

..  +J 

CN 

O   H 

0)  43 

0) 

03 

tt)    03 

tt)    0 

0    0 

tt)     *     tt) 

•H 

« 

•H    CO 

>4H 

r-i 

P 

P 

p 

p 

p 

p 

h   to  n 

a>  to 

rH    55 

0) 

rH 

•H 

•H 

•H 

0) 

•H     >, 

•H     >, 

•H     >, 

..    o> 

■d  (3 

u  w 

o 

0) 

fi 

1 

0) 

1 

d 

1     4-1 

1     4-1 

1      4-1 

•d  mh 

•H    0) 

1     CO 

c 

to 

43 

U 

43 

•H 

43  -H 

43  -H 

43  -H 

P     O    rH 

—. 

P     tQ 

0)     1 

03 

* 

ft 

•H 

ft 

> 

ft  o 

ft  o 

ft  o 

tt)     J3     tt) 

^~- 

P     1 

to  w 

-^ 

-p 

l« 

+J 

03 

rH 

05 

0 

03    d) 

0)    d) 

03    tt) 

P      1      (0 

4H 

a)  a> 

3  10 

to 

t-t 

m 

U 

ft 

U 

u 

U    ft 

P     ft 

P    ft 

<U    0      1 

rH 

>  to 

*> 

0  D 

I 

c 

0) 

■H 

&  CO 

d>o< 

0>CO 

0>  to 

CP  (0 

03  43    * 

0) 

0     0 

<d 

e  o 

<H 

•H 

n 

rH 

* 

: 

* 

= 

*  s 

*  = 

*  = 

••  -P  «d 

CO 

••  o  -d 

"  ? 

1 

1 

i 

(0 

^  '   n 

6 

o 

0) 

CI) 

> 

1 

0) 

0) 

0 

tt) 

tt) 

>HT5 

4H 

?   •• 

c 

>  " 

(0 

M 

03 

Q> 

& 

ft 

& 

ft 

ft 

OH    •• 

rH 

0 

0 

3 

03 

H 

^ 

>> 

>> 

>» 

■d    «J 

0) 

■0    »tH 

? 

•d  fa 

0 

6 

•d 

+» 

p 

P 

P 

P 

£     *     0) 

o 

(0 

13   rH 

0) 

C  J 

3 

P 

1 

1 

•H          TJ 

p 

•H     d) 

c 

•rl    W 

1 

a 

a 

6 

e 

g 

>    f3    O 

a) 

> 

*   to 

»  to  * 

■d 

s 

0) 

0) 

0 

0 

0 

i  -h  a 

03 

03 

1 

13 

V 

4J 

p 

P 

p 

P 

43 

P 

43  -d 

43  -d 

CO 

0) 

p 

•H 

•rl 

•H 

•H 

•H 

ft   tt)  -O 

to 

■a 

ft  c 

a> 

ft  c 

C 

to 

^ 

•H 

| 

1 

1 

| 

1 

Kflfl 

o 

o3  a) 

^ 

03    V 

O 

^ 

p 

1 

+J 

P 

P 

P 

P 

MOO) 

p 

P    to 

03 

P    10 

-P 

43 

S 

3 

n 

S 

S 

d>  33   to 

03 

u 

tn  — 

2 

d>~ 

P 

C 

ft 

0 

0 

0 

0 

o 

1 

u 

3 

&i 

03 

0) 

cu 

0 

0 

d) 

P 

■coo 

P 
0 

03 

P 
■d  o 

w  p 

<d    0 

43 

0 

U 

d> 

£ 

& 

& 

ft 

& 

O   <H  TJ 

>  -0 

o  c 

J 

0    C 

M 

ft 

* 

p 

p 

p 

P 

p 

43 

o 

C 

43  — 

E 

43  ~ 

1 

P    ft 

1 

0) 

P 

P 

u 

■d 

d 

•d 

d 

d 

a)  o 

ft 

to 

a»  -d 

<u  >d 

(0 

-d 

T) 

T3 

d 

■d 

6    O 

03 

^ 

e  c 

6    C 

> 

03 

03 

os 

03 

03 

<W   rH 

e 

4H    03 

>W    03 

MH 

0)   ^ 

0)  ^, 

0)  — 

0) 

> 

> 

> 

"> 

> 

■d 

■d 

■d 

•d 

p 

P 

p 

p 

P 

Section  5.5  The  Program  99 


o  CO                                                                                            I 

u  xi                                                                 =    n 

<t»  co   o 

o  -o    i 

S  +j                                                                    o  co 

CO  -H 

u  «h 

CO  (0                                                                                                                   43   13 

45  +J    0} 

+J  0                                                                                                                            CU 

H              —  -P                                                                                      o * 

o          g  <w  * 

4-1                 CO  M 

-P  O                                                                                                                            -H    +J 

<D                  -H  4-1                                                                                                                    0)     CO 

o           "d  o>           «^      ^                                              <o  43 

C              C  <0              to  —  —                                                      h   ra 

O  O               O  ~  <-*                                                                    I 

ViO  CVht-csi                                                             cC    CO 

id             cu  <tf  co  co                                                       co 

43  ~          CO  h  — «         ••  •O  •O"                                                                 ^    3 

+j  ^        _  CO  ~              O    O                                                          co    o 

O  ~  fl-       -  C   C                                                       -P   E 

>.        <N  B     4J    >,         g    -.    ••                                                                     C    •• 

•P    CO                CO  -P    O                CO                                                                             W> 

pi  43  *      -d  cx-p«j«j                                          =    -p 

•H  V                O  -H    a)               -H 

oec  o^e-o-o                                       tj 

o«  co  co       ••  h*j  «      t)  B  t!                                              ^ 

to  p  -P        C   co   co                                                     <0 

>!   O  -h         a>  >JS-HOwcn                                                       O 

O    O    I          TJ  U    O     I          O  —  —                                                            43 

•H   43    CO           O  -H   43    CO           CO                                                                                        >, 

puu>C  Pn  m   >        co  co  a>                 ~                               co 

=      =      -H  =s-H—  ■dT)                        —                                            .* 

£              4-»        <-  S-POO                   —                                     I 

OiH-HCU  OrH-HTJCC                          —                                                 6 

TJ-HCOTJ  -d-HCOC!                                    «—                                           O 

CCCO  fifl          fi         IID'D'                   —                                      H 

■H                  CUC'-  -H                  CO           CO    CO    CO   ~                 *-                                             *W 

S+jcq-^^>+jco—  —  ^^  43                                  i 

C           I                ~  ?                fl           I                            —                w                                         v 

rH-HCUO-—  OrH-HCPCHOj                    CU                                                 C! 

—          iHOCOW—  -OrHOCO-HO                          ^M                                                -H 

>njaDnj>C(Oft0  —      c       a)  iw                          m 

OOI           O^O-HOI  O<0                h  ^  -P    <U         -^                     •—    I 

•Ol-dE              -d  »          I    *d          g               $3          0    ft  CO    H          S                     >-P 

C         £3    £3         ••         COG  £3    G         ••         H    d)        +J    0)  H   ••         O                    O    <D 

•HCU-H                         O  -rl  CO           CO  -H                         O  43           <U    CO    01                 TJ                        TJ    CJ> 

s  ~  43  4-1      >       c>  -o  —  g  <w       s      <«>       na-o?       c              a  •  • 

>,4JI            O  ~    <d  O    >,  -P     I            O  ~                            —    ••    O          -H                      -H    > 

aii^'dft-PM-iCiU'Ofta  «os               S-p 

■d    X  -P    O         £3    CO    to  rH  ^-X+JO          (30)0                    —   O    £3                    —              —        -» 

O  —    CO    -P          -H     CU    C     <D  —    CO   .p          -H    CO    O                         O    fc  -rl           CO          «           CO                 ~ 

£3            CO   -rl            £    43   -H     10  O            CO   -rl            £    43   rH                           >H     flj     £           Tj           43           Tj   rH           43 

^■o  x  -d           «-ii  ^■043'0           »-*-                <a                o       co       o  co       co 

ficoco        TJ         co?  nJCcoco        -O                                  "O  -O         £3~<U         C43         co 

O-HII            £3—  >J(fl  l-HII            C'-O                       4JC3C          —con         —    «J           n 

nxi+jfi        coemn  coxiP£3        coen                 ococo            -p«w           rH       iw 

it      I      CU     01            CO     CD     g    T3  -PIC0CO            CO     CU     (fl                           (3C0C0            CU     CU     CU            CU      I             CO 

i    ai   co   cu       —..p«_-..  cu   cu   co   cu       ^-+j^-                 ^«_-^       t)  h   ^       tJ-P        ^ 

>SIM                    -H  rH^I^                    -rl—                                                            O     «»     ••             O     <D             •• 

COrHCOOg-d  COrHCOOg                                         <W                           flTJ                   J3C0 

{3k)coco        co-PC  tj  k)   co   n        copp                 -h                   !••>         I    ••        * 

i    >  s  ••      +j  o  iii  i    >  d  ••      4J  o  «               —               cooco           o 

QJIO>-H(3C0  (0IO>-HC3rH                                                        -PCOTJgaj'O 

cocogp       ^.w.^  cocog+J       —  «-'  —                                    cotJC        (OtJ        (3 

■3    rH     ••  -              —  pj   H     ..  k             w                                                                      ,H     Q   -H            £3     O           -H 

oft>=*          <«  o  a  >  %          M-i                                   coj3>co(3> 

g   -H    -p                 +>   -H  g   -H    +J                  P  -H                                                           TJ                         M 

+)^-                 d)^  4J—                 CO—                                                             "OTJ                "OTJ 

(3iH                   rH  J3i-i                   rH                                                     C3CJ3CJ3C 

j30                       ^  00                       ~                                                              0COCO0COCO 

lUg  <4-|g                                                                                                    lw     tfl     CO           4-1     CO            CO 

<p^  cu_-                                                                   co^^co—       — 


100 


THE  GRAPH  EXAMPLE  Chapter  5 


0)  ~  *- 

to  —  "» 
o  4>  >— 

ONI) 
.C  -rl  N 
O    W  -H 

=      I    to 

C     i 
=      -H    $3 

•H     Ifl     H 

o  e  <o 

eu    i    e 
•^  I 

M<H     ft 

O    0)    o 

•HH+J 
pn  ..  .. 


O  H  o  o 

•O   -rl   T)   "O 

c  c  n  c 

•rl  -H   -H 

>    -P     5     5 

>  H  -ri   T)  fl 

O  rH     O     C     C 

c       o   I    to  w 

■H  I     >0  -'  -' 

*         g  -S    X   * 
0)  --  ^!  M-i 

•d  :*p   i    "    ' 

0  i    u  «-*  «- 

a  x  p  o  ~ 

^«-    «    |J     91    01'- 

4)  -H    O    O  .C 

0>    T3    ,C    TS     ft    0<   CO 

•O    G    to   4>    X    >^  4> 

O    -rl      I       I       I        IH 

a  a  -p  c  +j  +j  M-i 

1  |     <D    4>    CD    <U    4> 
0)    CD    10    4>    tQ    10    U 

>  3   i    n 

OH    d)    o 

g  id  oi  to  4i  u  ^ 

i   >  a  ••  *o  tj  o 
a)   i   o  >  o  o  -o 

to   <u   6  -P   C   C   fi 

fl   H    ••'  -H 

O  ft  >  %  -o  -o  s 

g   -H   +J  C    C   _ 

+J  ^  4)    4)  T3 

C  pH  to    CO    C 

g  jj        >_^  a) 

WE  « 

■d 


Section  5.5  The  Program  101 


5.6  Problem  Set  #5 

Questions 


1 .  Assure  yourself  that  you  understand  the  graph  code. 

2.  Write  a  function  that  finds  any  nodes  with  no  connections  to  other  nodes  and 
removes  them  from  the  graph.  Write  another  which  clears  the  graph-window 
then  uses  map-over-arcs  to  display  only  those  nodes  which  are  "nodel"  for 
some  arc. 

3.  Extend  the  program  to  be  able  to  deal  with  a  larger  area  than  will  fit  on  the 
window  at  one  time.  You'll  need  some  mechanism  for  moving  the  graph  win- 
dow around  within  the  entire  space. 

4.  A.   Write   a     :  highlight   method   for   nodes,   which   puts   an   already 

displayed  node  in  reverse-video.  Now  modify  the  functions  mouse- 
new-arc  and  mouse-delete-arc  to  highlight  the  first  node  that  was 
moused  while  the  program  is  waiting  for  you  to  choose  the  second,  and 
un-highlight  it  when  you've  chosen.    Fix  up  mouse-move-node  similarly. 

B.  Write  a  new  mouse-sensitive  operation  which  has  you  pick  two  nodes 
and  then  highlights  all  the  nodes  in  the  shortest  path  between  the  two 
chosen  ones  (where  "shortest"  simply  means  containing  the  fewest 
nodes  —  don't  worry  about  ties). 

5.  {Hard.)  Make  the  arcs  mouse-sensitive  too,  but  modify  the  mechanism  so 
that  the  area  considered  part  of  the  item  is  not  an  entire  rectangle,  because 
that  would  include  too  much  area.  Allow  specification  of  parallelograms,  or 
something  like  that,  so  you  can  tighten  the  mouse-sensitive  area  to  be  just 
around  the  arc. 

6.  There  are  a  number  of  problems  with  the  code  as  it  stands.  Here's  your 
chance  to  improve  on  the  teacher's  work. 

A.  Any  operation  which  requires  that  some  part  of  the  display  be  erased 
currently  causes  a  complete  redisplay.  This  is  really  unnecessary,  and 
quite  unattractive,  especially  if  there's  a  lot  of  stuff  on  the  screen.  Fix 
the  deletion  commands  to  do  minimal  redisplay. 

B.  Currently,  if  two  nodes  are  connected  by  an  arc  which  cuts  across 
another  node,  the  line  for  the  arc  just  runs  right  through  the  node.  Fix 
the  :  draw- self  method  for  arcs  to  be  smart  enough  to  go  around 
obstacles. 

7.  Write    a    new    program,    borrowing    whatever    portions    of    this    one    are 


102  THE  GRAPH  EXAMPLE  Chapter  5 


appropriate,  for  displaying  trees.  One  important  difference  should  be  that 
instead  of  having  the  user  specify  the  location  of  each  node,  your  program 
will  determine  their  locations.  That  is,  the  root  will  appear  at  the  top  with  its 
inferiors  spread  out  in  some  tasteful  fashion  below  it. 


Section  5.6  Problem  Set  #5  103 


Hints 


1.  Play. 

2.  The  first  function  should  loop  through  all  the  nodes,  sending  the  :  delete 
message  to  any  which  have  no  arcs,  and  then  refresh  the  graph  window.  The 
second  should  clear  the  graph  window,  then  use  map-over-arcs  to  loop 
through  all  the  arcs,  sending  "nodel"  of  each  arc  the  : draw-self  mes- 
sage. 

3.  Give  the  graph-window  flavor  two  new  instance  variables  to  indicate  the  x 
and  y  position  of  the  window  relative  to  the  graph  area.  Now  the  functions 
concerned  with  node  positions  need  to  convert  between  a  node's  apparent 
position  and  its  real  position  by  adjusting  for  the  window  position.  Four  of 
graph-window's  methods  (: draw-circle,  :  draw-line,  rdisplay- 
centered-string,  : primitive-item)  will  have  to  convert  from  real 
node  positions  to  apparent  positions,  while  the  : mouse-click  method  and 
the  function  mouse-move-node  will  have  to  convert  from  apparent  to  real. 
The  former  four  are  all  inherited  from  some  other  flavor,  so  for  them  the 
easiest  thing  is  probably  to  define  whoppers  which  adjust  the  arguments.  For 
the  latter  two,  on  the  other  hand,  we  did  the  relevant  definitions  ourselves,  so 
we  can  change  them. 

The  whoppers  converting  from  real  positions  to  apparent  positions  should  be 
prepared  for  the  apparent  position  being  off  the  screen  entirely.  The 
: draw-circle  and  : draw-line  methods  "clip"  (they'll  even  do  the  right 
thing  if  the  circle  or  line  should  be  partially  visible),  so  you  can  just  pass 
along  any  bogus  arguments  without  worry.  The  :display-centered- 
string  method,  however,  wraps  around  when  given  off-screen  coordinates, 
so  in  this  case  you  should  check  the  apparent  position  and  possibly  skip  the 
whopper  continuation. 

(You'll  have  to  make  a  new  instance  of  the  graph-frame,  because  the  new 
graph-window  defflavor,  with  two  extra  instance  variables,  is  incompatible 
with  the  existing  graph-window.) 

4.  A.   The    : highlight  method  should  draw  a  filled-in  circle  in  xor  mode. 

The  basic  idea  for  the  mouse-!...]  functions  is  to  use  the  : highlight 
method  once  to  highlight  a  node  and  again  to  turn  it  off,  but  there  are 
two  kinds  of  complications  to  watch  out  for  that  could  leave  you  with  a 
node  turned  on:  the  :  refresh  method  clears  the  screen,  thus  remov- 
ing any  highlighting  that  may  be  present;  the  new-arc  and  delete-arc 
functions  have  several  failure  modes  (the  parts  with  the  beeps)  that 
skip  portions  of  the  code. 


104  THE  GRAPH  EXAMPLE  Chapter  5 


B.  Add  a  new  type  of  typeout  item  to  call  the  function  mouse-find-path. 
The  control  structure  of  mouse-find-path  should  look  roughly  like  that 
of  mouse-delete-arc,  and  you'll  probably  want  an  auxiliary  recursive 
function,  say  find-path-to.  A  breadth-first  search  will  be  the  easiest 
way  to  find  the  shortest  path  (because  the  first  path  you  find  will  be 
the  shortest);  you  can  use  the  mark  instance  variable  of  arcs  to 
prevent  looping  in  the  search. 

The  key  issue  here,  and  the  reason  I  call  this  a  hard  problem,  is  compatibil- 
ity. We  want  to  use  the  bulk  of  the  existing  mouse-sensitive-item  code  to 
save  us  the  trouble  of  duplicating  its  functionality,  and  we  want  to  modify  it 
to  provide  the  new  features.  But  at  the  same  time,  other  programs  will  be 
using  the  ms-item  code  and  counting  on  it  to  behave  the  way  it  used  to. 

My  approach  is  to  first  replace  the  hollow-rectangular-blinker  that  is  provided 
by  the  basic-mouse-sensitive-items  mixin  with  a  polygonal-blinker,  a  new 
flavor  of  blinker  which  can  draw  itself  as  any  closed  polygon  (imitating 
hollow-rectangular-blinkers  as  a  special  case).  Then  I  define  a  line-item 
object,  and  arrange  for  the  polygonal-blinker  to  draw  itself  as  a  squashed 
hexagon  around  ms  items  which  are  of  type  line-item  (and  as  a  rectangle 
around  all  other  ms  items).  A  number  of  basic-mouse-sensitive-items 
methods  have  to  be  modified,  but  most  of  the  changes  are  of  one  very  simple 
kind:  references  to  individual  ms  items  are  replaced  with  calls  to  a  macro 
which  just  returns  the  item  if  it's  the  normal  type,  and  extracts  the  appropri- 
ate information  out  of  it  if  it's  a  line-item.  The  only  substantive  changes  are 
to  the  :  mouse-moves  method,  because  there's  a  new  way  for  specifying  the 
shape  of  the  blinker,  and  the  typeout-mouse-item  defun-method,  because 
there  are  new  rules  for  determining  whether  the  mouse  is  over  a  particular 
item. 

Now  all  I  have  to  do  is  change  the  : draw- self  method  for  arcs  to  provide 
a  line-item  as  an  argument  to  the  : primitive-item  message,  and  define 
the  "Delete"  operation  on  mouse-sensitive  arcs. 

(You'll  have  to  make  a  new  graph-frame  to  put  all  the  changes  into  effect.) 

A.  The  deletion  commands  should  surgically  erase  exactly  the  nodes 
and/or  arcs  being  deleted,  and  leave  the  rest  alone.  You  can  erase  the 
nodes  by  drawing  a  filled-in  circle  in  andca  mode,  and  the  arcs  by 
drawing  over  them  in  xor  or  andca  mode. 

B.  Open  problem.   I  haven't  thought  of  a  good  way  to  do  this. 
Done  as  "The  Tree  Example,"  chapter  7. 


Section  5.6 


Problem  Set  #5 


105 


p 

? 

n 

0 

1-\ 

■0 

0 

c 

1 
1 

in 

•H 

1 

ft 

* 

U 

CT> 

P 

* 

CO 

W 

^ 

^ 

4H 

rH 

g 

^-~ 

:s 

CO 

(V 

* 

0) 

0 

CO 

rH 

03 

0 

13 

A 

CO 

P 

--. 

»-. 

C 

5 

O 

T3 

(0 

^-~ 

«-* 

■H 

Hi 

M 

0 

CO 

^ 

> 

rl 

h 

l 

CO 

P 

CO 

co 

CO 

m 

<a 

co 

T) 

rH 

h 

« 

A 

0 

CO 

4H 

CO 

■— 

-p 
1 

C 

■a 

CO 
in 

rH 

o 

CO 

iH 

T3 

•— ~ 

T3 

H 

C 

CO 

0 

- 

* 

CO 

T3 

* 

* 

»-• 

c 

* 

to 

0 

» 

CO 

» 

0 

CO 

n 

0 

0 

u 

u 

C 

TS 

CO 

73 

<c 

o 

0) 

•H 

r-\ 

n 

G 

T3 

a 

rl 

c 

rH 

a 

•iH 

0 

•H 

rfl 

0 

0) 

0 

CO 

5 

fi 

s 

CO 

rH 

■0 

a 

co 

1 

1 

0 

-d 

| 

0 

■~^ 

k 

s-,43 

rl 

c 

CO 

c 

ft 

(0 

ft 

ro 

CO 

> 

c 

0 

(0 

rH 

<0 

1 

CO 

0 

M 

0) 

T3 

5h 

a 

H 

rl 

^< 

g 

0 

A 

Cr> 

CO 

Cr> 

co 

(V 

4-1 

» 

* 

•H 

* 

>  •« 

M 

a 

■0 

T3 

T> 

0 

1 

c 

CO 

a 

0 

c 

c 

a 

ft 

CO 

0 

0 

CO 

9 

CO 

0 

— ' 

<u 

H 

CO 

4H 

CO 

e 

CD 

1) 

•o 

-a 

££ 

0)      rl 

43   tn  O 

P  P 

a>  Pi 

•0  43  -n 
P!  P 

«D  * 

co    M  0 

CO  o 

3     >  rH 

o  o 

>>  o 

-O  P 

P  c 

(0  pi  p 

43    O  P! 

P    U  <0 

-0  > 

CO 

co  P  P 

U  -H  43 

•H  tJ> 

3     CO  -rl 

tr  >  g 

CO    o 

Hg- 

o    • 

P      O  rH      C 

2  P  -rl 

A  X 

CO  •   -H 

-  co  co  e 

>,   &>  CO     I 

P    <0  2    &> 

•h  co  o  a 

rH     CO  g   -H 

(0     CO  rH 

a     g  CO   rH 

O  43     O 

•H     CO  P     U 

P     O  O 

O    ft  43    CO 

PJ   I  p   I 

3  >>-H    £ 
4-1      I  >   43 

43  co 

■O     ft  rH     (0 

CO     10  rH   rH 

■O     rl  O   <4H 

co    tn  u    •• 

co    i  cj    > 

P!  P  to  P 

co 

co  co  o  *0 

43    ••  -P    P! 

P  (0 

TJ  P 

rH     C  P!     H 

rH     <0  CO     <0 

«5  -H    43 

CO  C      I 

CO     O  CO    rH 

CO     ft  >    rH 

■d     I  P!    O 

■H       X  O      rl 

>  I  O     U 

O  43  to 

rl       ft  CO        I 

ft     «0  rl      O 

rl  O     'H 

tj>     &1  g       CO 

Pi        I  03 

•H   P  CO  43 

>  CO  43    •• 
O    CO  > 

rH     ••  13    P 

r-i  t-\ 

O     ?  P»     CO 

4H     O  O     P! 

T3  »   -H 

CO     Pi  X 

rl     "H  +J     'H 

e    >  H    g 


—    P!    to 


>    P 


>  O   O    X    CO 

O  -H     CO 

TJ    co    co    g    3 

P!    O    O    I     O         tu  -H 

•H     ftftCO     g^    OH 

>  I     i     co    i     S    C    ft 

i     X    >,I1H)    O    id    i 

43     I       I      O  -H   T3    P    P 
ft4343OC0P!C0-H 

irJftftum-HCC 

}H    *    10    ft  43    >  -H  -H 

0>    rl      rl I         I 

Cn  tr>  >   >   >   co  P 

M—  —   PPPrHrH 

O  >-  «-              43  P> 

>  (0  (0 

10  +J  IH 

rH  P  CO 

Uj  CO  -O 


S    *  to 

i  P 

•S  +•  6 

ft  co  O 

It!    -H  rH    4-1 

»H   rH  -H       - 

01   10  C   — 

^     I  ' 

»       CO  ft 

ft  I   ft 

to    >,  U    i0 

CO    CO    P  CO    g 

CO     CO      I  4*      I 

rH     O     g  P!    P 

43     O     CO  -H     G 

(0     U    P  rH     O 

•H     ft-H  43    <4H 

u 

Rl 


CO 

CO     I 
•H      I 

TJ  43 
>0    ft 

rl     (0 

rl 

>>    C7> 

X    >, 


u   co 

-^  a 

O     I 

^? 

<0  43 

rl      ft 

■O    <0 

••    U 

&> 

Bx 

T3 

Pi  I 
•H  — 

I  U 

43  CO 

ft  ft 

(0  ft 

rl     O 

&>43 

I 

rl       CO 

CO   p) 

ft  Pi 

ft-H 
O  P 
43  Pi 
>    O 

4H     O 

Q)    ^ 

T3 


106 


THE  GRAPH  EXAMPLE 


Chapter  5 


a 
i 

X 

to 

a 

1 

1 

(0 

1 

* 

r 

ft 

Ifl 

rl 

cu 

Cn 

T3 

CO 

e     — 

.-~ 

0 

H 

o     — 

cu 

Pi 

P           CO 

N 

cu 

0          ft 

•H     N 
CO   -H 

cu 

,£3 

p    1 

£1  —    I 

1 

CO 

P 

A  >> 

CO    >, 

c 

1 

CT>    1 

P   0    i 

•H 

c 

kl 

•H   A 

A    <XA 

tn-H 

0 

u  a 

0>   i     ft 

M 

Cn 

4-1 

10 

•H     >,   « 

§ 

M 

— - 

p  u 

P     I     P 

1 

c 

4H     0> 

^ 

43    &> 

i 

0 

cu 

^-^ 

V 

^-» 

ft  ft 

P 

i 

•H 

N 

cu 

rH     01 

P 

0    it)    6 

4-1 

ft 

P 

•H 

N 

&>    ft 

-C 

P    P    0 

CD 

0 

■rH 

CO 

•H 

tn 

tnP 

rH 

P 

CO 

1 

CO 

c  >. 

•H 

-P        -P 

<-» 

0 

PI 

1 

•rl 

01 

4h   ft  0 
d)    0  A 

^ 

*-» 

> 

> 

a 

■H 

Pi   — 

P.    <W 

A 

CO 

CO 

P 

P 

CJ> 

•H  -^ 

P    O 

1 

rH    P 

a 

0 

s 

tH 

^~- 

tn  — 

CO     CD 

V 

I 

ft 

X 

►, 

r 

cu 

ifl 

—■ 

U  — 

—  -0 

Pi 

6    i   — 

i 

P 

Pi 

e 

co 

(fl     CO 

•H 

0)  ^ 

>> 

>1 

^- 

1 

1 

c 

0 

a  o 

--» 

rH 

p      — 

>>~ 

— 

- — 

•H 

Ifl 

p 

ft 

i   a 

t7»  — 

•H   —    CO 

CN   A 

A 

0 

4-1 

ft  i 

C    co 

>   — 

CO    0 

cu  0  ft 

>>  ft 

ft 

X  * 

+ 

+ 

cm 

cu 

CU 

X 

o  >, 

•H     0 

P   — 

•0 

« 

CO 

rH 

p   i 

U    ft 

CO 

ft?A 

CN     U 

(H 

co  X 

X 

0 

A 

••  A 

p   1 

*~*   0 

X   c^ 

Cn 

Pi 

00 

CO 

o 

0 

a 

ft 

co   X 

p  ft 

P    X    1 

o  s 

0 

a 

•H 

A 

3 

id 

S    ifl 

1     1 

A    £ 

—    I    A 

T—     T— 

(N 

P  w 

ft 

0. 

u 

0 

n 

0    P. 

T>   A 

tn 

A    ft 

►«>»>» 

p  H 

X 

s 

r 

= 

-0 

CT>  "O 

CU    ft 

—  -H   +J 

—  ft  «J 

PI    H 

•e 

C 

Pi  •• 

P.     lit 

.-.   q,  # 

e  m  p 

T—        | 

1 

A     1 

0 

rH 

•H 

■H 

CU    U 

^5  ^3   Cn 

cu  p  tn 

X  — 

~— 

~« 

cu 

T3 

■H 

* 

> 

>  > 

P    tj> 

P     1     -H 

p  tn 

T3 

Pi 

C 

0 

0 

ps 

■o  (u  h 

•H           P 

«-~ 

*-> 

—  H 

0 

•H 

"0 

T3 

TJ   X) 

CU    P 

•H   T3 

i   p  A 

«-^    CO 

CO 

>!  t>i 

C 

s 

P 

Pi 

c 

Pi  Pi 

O  A 

»    -rt    P 

a»  m  &> 

CU    o 

0 

O    H 

c 

CU 

■H 

CU  -H 

I     0> 

1      CO    (M 

>    CD  -H 

Pi  ft 

ft 

•H    W 

4H 

» 

rH 

■H 

10 

:* 

W    > 

>*-H 

D     fi     D 

•H   rH     P 

•H     1 

1 

rH    2! 

CU 

rH 

0 

rH 

0 

<o   p 

0    -H    tH 

P 

rH     X 

X 

U    W 

CJ 

CU 

■o 

Ifl 

ft 

■d 

^  T3 

rH 

•H     •• 

■H      1       1 

1        1 

I 

1     CO 

Pi 

CO 

Pi 

0 

X 

Pi 

>>  Pi 

ft  M-t 

CO            tn 

e  —  — 

?  A  A 

CU     1 

(0 

■H 

1 

T3 

cu 

0) 

co  o 

Pi    4-1    Pi 

•H 

tO    ft 

ft 

CO    U 

— ~ 

p 

4-1 

> 

Pi 

a 

1 

to 

I      CO 

•H    CD 

•H   iH   -H 

p  e 

H    <0 

<fl 

pl    CO 

CO 

rH 

cu 

•H 

?  2 

..     CD     P 

ft  CU 

■o  n 

u 

0    C3 

1 

c 

CU 

CU 

^^ 

A 

4-1 

CO    p 

..  p 

..   tn  tn 

a  o 

rH 

•H 

CO 

■o 

>>-P 

1 

+ 

+ 

4-1            CO 

•H 

••  as 

1 

0 

M 

*  — 

rH   -0 

s 

>  r- 

OJ 

CU 

CU 

» 

Pi 

X 

P 

0 

^^ 

0    CO 

<D     C     U 

O  cu 

0    X 

X 

*  " 

CO 

,X 

(0 

<D 

p 

CO 

CO          -» 

■S& 

CO   cu   cu 

CO    ft 

SS 

■o 

C     1 

1 

0 
•0  fe 

0 

1 

u 
n 

cu 

■0 

CO 

A 

a 

0        A 

ft          CO 

•H     1 

•O  ~  ft 

•H    P 

•H  ~- 

Pi  J 

B 

-0 

c 

CO 

CU 

X 

>\        cu 

*     X 

Pi         o 

> 

* 

•H    W 

P 

0 

•H 

1 

1 

1 

1        Vl 

1       1 

0>    1    .c 

1      P 

1    u 

*  w 

* 

-d 

Pi 

X3 

p 

C 

p 

P          4-1 

.c  a 

P 

co  ~  » 

A   cu 

A    CU 

1 

c 

— . 

1 

<D 

0) 

CU 

cu        cu 

ft    ft  (M 

»-»        i 

ft  ft 

ft  ft 

A   TJ 

to 

0) 

^ 

cu 

CU 

CO 

cu 

CO 

CO          u 

(fl   <0 

a) 

co  a> 

a)    ft 

<0    ft 

ft   Pi 

C 

CO 

> 

P) 

M 

P    P 

rH 

P    0    3 

u  o 

U    0 

(0    CU 

0 

^- 

p 

0 

rH 

CU 

u 

tn  0> 

.G    ft  C 

Cn  .C 

&A 

U    CO 

p 

e 

id 

to 

CO 

cu 

01          ? 

ft 

CU  S-H 

~  * 

—   > 

&)  — 

p 

& 

i 

> 

0 

■d 

T3           0 

W  P 

CO 

■H           P 

PI 

0) 

i 

0 

> 

0 

0          T3 

P  <W 

3 

ho   c; 

p  cu 

M    CU 

^  P 

J3 

0 

CO 

CU 

a  p 

c 

Pi           Pi 

a>  cu 

rH 

0 

CU    3 

CU    3 

•O    0 

M 

pi 

rH 

■H 

ftrH 

ft 

V    v    o 

ft  a 

ft  Pi 

0    Pi 

II 

ft 

0 

ft    > 

t) 

-0           * 

ft 

ft-H 

ft-H 

A  ~ 

a 

•rl 

p 

PI 

Pi 

0   M-t 

0  P 

0    P 

P 

P 

cu 

CU          -0 

J3    O  <0 

^  Pi 

A     Pi 

CU  T3 

§ 

H 

CO 

CO           Pi 

>  a) 

fi 

>    0 

>    0 

6    Pi 

i 

— - 

_          o> 

<W   0 

« 

4-1    O 

>H    U 

4H    tO 

<4H 

CO 

0)     w- 

0)  .-. 

0)  «- 

01  _- 

CU 

•0 

>0 

•o 

■o 

•o 

Section  5.6  Problem  Set  #5  107 


tJ>  4H    g 

a  in  -h 

id  en  P 

43  0)   43 

o  o  en 

—  O   -H 

—  -  SH 

—  »  to  A 

—  6  O                   Cn 

—  o>  >d  oi  -h 
H  -P  —  C  >  43 
O                                                                 -H  —                              -H 

X  >                        S              0>   0) 

1  X>  O  —        —                          H  43 

2  (3  fl  M-'-  p  01  P 
rH                                                        O  CO—  —        43              43 

Id                                                              O  -H    M  x-  (N           tn                >    to 

iv  ?   <t3   a*  a>       -h                 w 

>                                                    —           0)  --           ••'dt)          H                  (D«) 

P                                           -»_-  =     —  POO43t00) 

—  •  —  43  —  (3   C         0>             *h 

10  =  >,         (N  =T3>>t7>e H  O    O 

2                "O                P                        0>          -d  X)                P    0)          -H    01                       43 

•H                  0)                  13           X          Xl           0)  0)                  C4J«H+)ldfl           ••                  (DIM 

•O"                    &1                 -H                           OCn  &1                 -H     0)           43   -H                                                43   rH 

•d             J3             06CJ3  a             O  h   6  d>      x«  xi        o>            P  oi 

w            ro            o<  —  o>       ••       id  id            o*o>o>-hxii3i3xi                 to 

43                    =     P                    43  43                    x»  P  43    13    01    0)          O               (3  P 

t0                   O                  M       •   -H            0)            O  O                  4*           -H     ••     O     01     t0            fi                  -ri   -H 

o                         o  o    i       xj  o  o>    i        o  «—  -- 

ft              •-             -H    w    0)         O  —             -H  43    0)    <u    <u                   -a              ID  43 

>,                               Pn    10    >          G  0.          >  XI    to    01    0)          C               too 

=             -H  rO-HO---XlXlO>—    3-H 

to                        SS+jt-  SPPGOOto        —  <d43 

O                                  O   H     J)   -ri            IV  OrH-H-Ofifi^—    OS 

ft                   •d-ncio'O  xi  -h  o  to  >o  (3           —           ~a> 

X                         CC         C         O  fl    fl    H    C    fl    Hi    ffO1--       -fl     - 

•h        iv  u        c  -h        <d  o>  oi  to  oi  o>  —  ft      —       43 

—  o>                     s  p  43  to       ••—  —            s  p       toto^-^^njiu       43<vto 
>ih                         J3-PI            —  >                j3Q)i—                     ajtowiu 

OO                               rH-H           a)           O  —  O                 rH   -H   43    0>           (3w           (343           0>    0>    fc 

•K3     U           —                  rH     O     H     10            H—  XI                  rH     O    -P     tO   —  -HO            H   —  —    W    43    «W 

(3 -h        >             id  ft  o  3        id*  G             (dft       3  ft---        rJ        v  <h        o> 

•HO          O                OliwO         %      O  —  -H                O     I     M    O    0)    id               +JCPIV+JW 

»i       -o—        1-d       6           -d—  >—        i  flO  Em       C       o>  d>  o>  n  43  •• 

—  C          fi>          C    C    01    ••         <VC»  S          B    B  ih   ••  fl    H«          H    O  H    ••    tJi 
■ri       -ho        oi  -h  xl             o  -h  o  o>  o        o>  -h            —  o  43             u  01       -h  id 

—  I           >  -d  —  43  <«    O    S          C    >  Xl  Xl  Xl  —  43  «H    tt)    >         <wS                ft-dSH 

■p-d          i3  >.  p  i   c  o  —  id       a  ocj^Pi-doc                 —  ••  o  43  x> 

430)           0>  -H            I      U          Xl    ft  -P   <4H  -H  J3  -H           I     Vl    CO    tJ>ft                                   Xl    d>  -H 

0>  rH           T3»XPOMC0)t0rH>  -'SXPOCCOO                         —    OCI-HTJ 

•Hi-I           O          ^<UP0)-Hll)l3a)  ---01-P          -HMO                         OM-H43 

rH-H            CP            0)-H43>43-Hl0+J  OP            <V-Hrl*ftrH                           U     *     &     "    Q> 

43<w        —  43  "d  43  T3  -P         —    I      I    43  H43-d43,da>         — —                     id                     > 

tj>i             d»i3tna)0'd        0)>o>  ^011310(1)43^                             ■d'dnJ 

•H     ^            O   -H   -H      I       I             C   —  M     Id   -H  I      H   -H      I       I     +J     C   —    O                          P     C     C 

43ld            VlrH43-P(3a>a>aidiHrH  11   H    ,Q    (J     B     O     11     g     tl                           O     0)     0)    P     o 

••>h        <d43ia)a>43toa>E'd43  P43i<va>        toaiid                 i3tatorJ>H 

■d        i&i<D(oa>4J»--4J«-'"&i  a)di<vtoa)tt)^-P»—               ^^^ftm 

0)    ••            >   -H     r>      I      H                  -H                  -H  rH   -H     ^      I      U    43           -H  ^ 

XI                 0)43rHil)Oa)e          "d          43  0)43rH0)O-PE                                    MH                P13 

OS        (3"idtototoaiPi3        ••  ■d"idioto        iv+ip                 -h             toid 

co        i        >0-oPoa>  i        >0-*Poo)               —           s 

^■d          Q)a)lO>O-Hflt0          0)  0)<VlO>O-Hj3rH                                       -nul 

a        io-da>eP43~  —  —       -d        mfl  m  B+)^ a> 

•d-H         B   O  H    ••  *     O  ^                   O  3    O  H    ••  «     W  ^-                                              P+J 

0>         OCft>*=          im              13  OCft>%=          iw                                         ^0) 

43                  6          -H    -P                 +J   -H  g          -H    P                 P  -H                                                     BH 

■p*d           "dP^-           o)^-           >o  xi-p^-           <v  <~-                                 <oo) 

0)CCC!rH                          rH                           CCfirH  rH                                                                OT3 

g    tl         B    V    B                    w                     O);30>rj  w 

MH     10             I4H     W      g                                                                  10  IM     111     E                                                                                                             ••>    •» 

•d           *d  *d 


THE  GRAPH  EXAMPLE  Chapter  5 


a  - 

z  I     U 

"2  £  ~ 

0)                                    G  XI  ~ 

O                                   <w   O  > 

0)    fl  *« 

0)                                 to  —  C 

5            3  3  -     ~* 

O                                       sO)  X\                &•* 

u~t                                      j5  tj  +J               to    tr  — 

o  —  —                 *  £  D,&~ 

•H   ~  —                                         03  +JO—&>  — 

jj   ^  ^                                 -Q   -H  MT>-H~ 

•ho>—              c^  £     5  ~  ^  ~ 

"58              Z*  u    «"* 

•>    C     I                               0)0)  01  ^  ^    C  T)    C 

tr               -H    flj    <tf    H                              "A  -H   +J     _   ,G  '      ~  -M 
G 

5 


a 


a  ji  i   1  *  xi  fc  "  ""  'd  "P  5  ? 


£  u  •  •  •  •  «  -p  *  ^  >  "2  h  tJ  '2 

R_,00  ft  P  O   H     01   'H  O 

■rt   £  -O    T3  K  £  -O-H-H03T3OH0) 


El*  So  c2      cfiiflfl 

.5   -H  I     ^  -H                  0>    4>    01    O     O 

S+J  55  e™_  ?  c  o  ?  ™~~ 

"*              jj  irtfl  +J0)  S              H  'H    >,  41          OC"0 

n                  2     O  C     C  -H    .2  O                  rHO            01   —   P-Hfi 

.2—       it)  ~  ~  ft  *o  -h—       i>d-HE<up      ^ 

n.rliiu  -^  ^  O-H  i    n  +j  tj   tn  G   ft  «> 

5   ?  .2  «  +j  oioi->  ft  "        ^<U+J0)-HV4>wO  — 

ti  0>g>t!)«  a   a  m  -n  .G&>o>oia>.P~P~ft~ 

oSh   i   3  tr>       -P  -H^iHttfOttig  t»w 

i  »  *  w  £  <u<i)*  c      g  ^  "  IS  S  "  S  ?!  ^,  i 

i         >  2  ••  T5T30  -H        O  I         >3l'8^2^ 

a           .j    jj  C     C  I              I  S           "H    +■>                   4J    •" 

B  T3  -m  i-  §§A  a     2  ^  "9  ii  w        iS  w 

fiflH  0101CP-O  gCH  rH 

ih  a  §  tod*-  "S016 

5  .        +J  t3 


Section  5.6  Problem  Set  #5  109 


u       •-  a) 

o         -P  73 
>w         CO 

o  o 

—  o>  03  +j  ••  o  <«  03 

~—  +J    .C   -H     M     W    4-1           .C 

---X  -h  .p  ,c  p  73        oi  -p 

.C          P  >,  O         -P  -H    O    •-  ,C 

+J            (0  I-H-H73           4-I.C-P-P'' 

me  -p  r-\   c  <w    i   p  w       tn 

«-•           a  -Hamo-paj-Hy-iaj 

0)                     1^  OX                    01     BHIH     01 

73            >       p  -hoj-ojo)            o* 

0  aim  rHg&i^aajojo 

C               C         E  ft  C    03    fl         3    3    E 

1  I  gfl+J+J  >0J0J0JH 
73  03  -P  -H  -rl  fi  4-»  3  3  ,C  <H 
C  0303  03  (0  03  O*  O*  -P  « 
0)                    P            03  ffl     >    +J     >     fc 

0)           ••  ,£(CK73-H.p0)ftp 

03                  >  +J^!03(0>wXX!OO 

73   —           03           O  (0           C            I      03    -P     ft  fe 

O  £!          P          P  ft  fi          03  .C    C 

c+j       g  ~  to  m  n  c+3   i  iH-o 

—      1(0            —   M  rHOXiO-O-POC' 

0)     P     ft                   P    73  «           4->            (0     03            (0     E 

O03                  CJiflfi  -HO)                  0)     tT>  -P           03 

p  x:  oj       ceo3  4->sp'P"C--p 

(O+j-o-hos  vio-pxjo-p-h 

•  •00         73  ~  •—  (0      ►  M-l    X         73    P    M 

••CC^  ftl)           1)      -fiW-H+J 

03             I     «  'ri     ^     O  P     03     fi    -P     (0           rH     X       • 

-oos+jihatj  u-iss       «       03       a»i-i 

0  P    03    03      I      E  O-P0373PE.C03fi(C 
fi     ill    C    tJlX    "fl  O     3    03   -H     03    -P    ,C           O 

1  M-PC  033D'3'«-P-P03-H 
73-003(0(00(0  S    ^           0)     I     -H      ►         .C    .p 

C     C     C    4->     ft    P  03+J03J-l£!l'4-l<4-(.PC 

0303O                  (OX  ^OI^SVOIWO           03 

03    O    0)    E          -P  C         -P    ft   ft  73    O           t*  73 

73  ~  ~  73    O  73    (0  rH               0)(0AJC-H 

—  C                  O     P     C     ft  03O.X0373--EO-H 

M                                              9    I     I     fX  «H    03     I  ^hlllfl-           OJUflOl 

P                                                 03                     I        I      03     S  P    -P     03                    <U    £    X)     P    -H 

(0                                             —    03   X    >     C   —    03  fi          73    03   ,C    -P           3 

E                                                    73    -P     03     P           G  Jl    O    >iri    1I4J           11+)^ 

03—co(0C3O'  >ofhsx!       axojo 

03                               XX5-HCO,+J03+J  (0           03OO(T>O-PP-P 

45                          +j+j          110*03^0  A    03    >  A    P    C    ft               I 

•P                                (0(OOSS03P03  >   -H    03    (0   -rl           O    03   ,fl 

(0                                   ftftPO30)«-'-'O3rH  C-H-P            0)    >*    73    -P     P    -P 

ft                                  I              75     C     C                    03   iH  (003(0^!03(OCCOlO 

I                                rH    P                         CO03O  ,CPP-P03(0OMHft 

rH                                   <0(0PPP0373rHO  —                                 -P     3     03     (0    MH     S                    031 

(0                   -hoooox       fi  03                        o+jfto-p'Ojxi'O 

■  H                                  +J    ~   4H    4H    <4H     ?            3  73                                  H03-H                           CEC 

P                                   P  O                                  03prH03>,O0)4J-H 

P                        *    ii    ft  C--             Xfim-o^+Jtniw 

(0                                  ftO  ~            03                   4->     03     03    -rl     fi            0}   -rl   -H   — 

ft                                         030  73                    (flXX+J-H+JErH 

CO   H  ~            O                   Jh+J+JP^0103S03 

P                                 -HO—  03CMC                                          (0            3    -P     03     03     3 

03&1                          C  7303                                  >,73ft-PT-l-HCXJa3 

fr           C                  X!lO>  O    73   ~                   ••    ,Q    rH            C                          +J     3 

P-H                   -P73C  fi     O   <N                    OlSX0373»03O< 

(073                  lOC-H  ICO)                  3..XOOP0303O-P 

4J            CO            ft03O  P73                  -H     O     >   -H     03    -P     C   -H     p     03 

—  -H+J                           fi  0)   -*    O                  73(OX*4-lCiHOX3 
03    <4H      I              PPO  X'-C                    C+JOS<4-l03Xft03.p 

0  ,C      I     £           OOO                                             ~4->03  •H00+J-HEO3W 
+J+JX+J           4h   4H    G                                             <—  O7303                 *4H            10373033           3   M-l 

l(0P(0-P                                                                      ~  ••     O   73                     l03,C73rHft3OO 

£!     ft    (0     ft    0)     ft                                                              —  CO—           .CX-P-rl-Pft           0>! 

•P     I      ft    I     t7>   0                                                       ^  O           C~          -P-P(0O(0EC>i          03 

(0rH73PO                                                                P  P     03           ~            (0            ft    03    ,C   -H     O           -P     03 

ftfllX    C    UH                                                  (0  flfl    tTH          ftCiT3-P          >,+J    01    3 

1  -H     O   -H    +J   —                                                               E^OOJ-H  -H73                   03            03     H 

73    -P     O    <«  C^C03C73O3£l+Jp-HO3 

CPrH>-  73                                  >    73   -H   rH   -H            03   -H    <4H     03 

•H(0.Q  OCW                  •H03l«CCP,PI^ 

"Wft—  ,C     03   -rl                   +JCOX(0-HI+J(0 

+J    ^  ^  fl.H  SOO4-I4503E 

C73  03                                  G(0'(0I-P03 

CC  EM-i                     H-PO)0)0^4373XIX 

y-iio  <«-h                 03fiS3P--p(0O 

03—  03—                         +J-H0303ftOft03P-H 

73  73                                 rH(0C3ft-P03POX 

—  —  <EO,O,(00373XJ<«» 


1 10  THE  GRAPH  EXAMPLE  Chapter  5 


-^ 

«-. 

ft 

ft 

"" 

^ 

> 

to 

0> 

0* 

G 

I 

T) 

(3 

0) 

0 

Cr 

to 

13 

Oi 

*"' 

o> 

0) 

to             -» 

r)                         « 

Cn 

•0 

0>              43 

<-~ 

<-^ 

0  43 

>              -P 

01 

C  P 

oi  —       id 

.-» 

•0 

0) 

1 

ft 

U  X         ft 

o 

3 

n 

G    U          I 

-  s 

c 

0) 

0) 

—  id  —  £ 

~   0) 

3 

43 

0) 

e  -v  o» 

— >  P 

43  ~ 

cr 

P 

T3 

•O                     rl        C 

e  -h 

•p  ~ 

to 

0 

O 

$3  —  id 

0) 

Id ' 

*-» 

o 

J3  ^ 

v  x  e  b 

P   to 

ft 

e 

u 

0    U           01 

•H    fi 

1  ~ 

0> 

«-» 

id 

O 

>  P 

4H    id  M  P 

0 

■o  e 

p 

P 

rl 

0>    Oi 

1       S     rl    -h 

to   u 

c    0> 

•H 

X 

« 

C   &>43    ••   id 

a  g 

•H    P 

^ 

* 

01 

43    0) 

u 

+»       g  *d 

o  — 

«4-l   -H 

«»s 

T3 

n 

c 

P  TJ 

T3 

to   id 

id   o    i   -0 

o 

1 

<u 

G 

Id 

1 

id    0 

(3 

a  p 

ft  u  P   id 

g  u 

o>  -o 

3 

—    O 

B 

p 

ft  C 

0 

0 

id   oi   •• 

g 

-  p 

to  c 

0) 

<-»    O 

Oi 

to 

U    01 

B         to 

01 

ft 

3    0 

3 

Oi    0> 

01 

Cn 

U  TJ 

•-^ 

—  -0 

O  TJ    ••    01 

•p 

U     1 

o  o 

cr  "O  to 

0 

id    C 

0 

rl      C                 0 

•H 

■p  -p 

6  0) 

o  ~ 

0) 

O    0> 

II 

II    (3 

MH    01    O    0) 

> 

ft  s 

«_» 

to 

G 

3 

01 

—  to 

1     to    U    3 

I     0 

J3  — 

a* 

-  o 

cr 

n 

< — 

0) 

43    i 

c  —  id  cr 

p 

•H 

o 

—  +J 

0) 

II 

T3 

P    Oi 

rl 

e 

3    0- 

■P 

o 

(3 

'      1 

p 

3 

a 

0 

ftC 

3  cr  tj  "O 

a> 

O  P 

X 

0)  P 

03 

„  A 

<D 

cr 

0)   -H 

C 

P    Oi    C    (3 

■P 

01 

0> 

C     1 

P 

b  p 

tP 

X) 

1 

i    cr  oi  —  oi  oi 

■rl 

cr  to 

c 

•H   43 

to 

0>    0) 

rl 

■O  TJ 

o  o 

S 

>  o> 

rl                   01       tQ 

1 

p  «- 

1 

rH    P 

a 

p  a 

id 

(3 

(3 

13    U 

0) 

Oi  — 

^-   to  «^  ^ 

— » 

■0 

0* 

•p 

Itf 

■H 

•H      1 

p 

3 

<D 

id 

(3 

{3 

(0 

<-»  rH 

•0 

to  U 

a> 

Cr  ft 

1 

1    T3 

o 

W 

43 

(3 

o  oi  o 

rH   -H 

n) 

>—  -p 

Cx> 

C     1 

01  T3    C 

4H 

~_- 

P   n 

rl 

rl       01 

•O    rH   -0 

•H    a 

-— . 

ft 

•H   -O 

M  -0  -H 

0 

1 

•H    O 

0 

0  43 

G 

a 

n 

M     1 

>     C 

1 

0)    4-1 

p 

43 

ii 

43 

>  »w 

4-1 

4H      » 

0 

u 

a> 

p 

-p  p 

o> 

0   -H 

..  — 

1 

■P 

P 

o>  n  P 

3 

a 

ft  0 

0 

rH    <W 

43 

id  43 

<d 

ft 

d  P  ft 

a> 

I     0 

0> 

»■"« 

rH   «-' 

0>  43 

P 

ftp 

ft 

O 

V    ft    1 

0 

c 

g 

0 

»-» 

O 

0) 

n  p 

m 

■d 

0 

3    i   -P 

cr 

■rl 

■H   -0 

cr 

rl 

<W    43 

d 

0>    10 

ftT3 

ft 

<D 

rH 

trc  s 

o 

p 

■P 

0) 

3  ft 

0) 

rH 

■H     O   ~ 

rH 

cr  as 

ft 

0)    id 

3 

cr  — 

■a 

e 

u 

•H 

n  ~  «--* 

T> 

rH 

P   rH 

■o 

1 

43    ft 

cr 

(3 

<d 

0  43 

0 

O  ~        ~ 

0 

fJ 

0>    ft 

0 

c 

P  «- 

•o  w 

•H 

C 

4-1 

>   TJ 

> 

43 

J3 

to  u 

43 

•H 

~_^ 

C  P 

4H 

Id 

p 

p 

01 

0)   o> 

ft 

1-1 

o> 

B 

0) 

ft 

O   P 

p 

tO   rH 

C 

0 

«w 

s 

4-1 

o> 

a 

a 

id  0) 

0) 

^^  ^-» 

3 

0 

<H 

4H 

•H 

p 

4-1 

rH    rH    43 

rH 

4H 

r-t 

a> 

01 

■H 

0) 

ft  —   P 

<U 

TJ 

•0 

•o 

01            -rl 

TJ 

w 

*■* 

w 

U             IS 

"■* 

Section  5.6 


Problem  Set  #5 


<T3 

Xi 

•O 

U 

^«, 

Cn 

o 

o 

«-» 

o 

^~ 

C 

0 

(0 

x; 

W 

•H 

u 

T3 

s 

CO 

> 

o 

U 

8 

d) 

p 

1 

i 

•H 

6 

o 

3 

co 

UH 

w 

H 

rH 

fe 

0) 

0 

CO 

2 

rH 

•d 

p 

i 

03 

xs 

■H 

0 

B 

>« 

0 

0) 

CO 

c 

0» 

CU 

P 

P 

X 

■p 

A 

•H 

CJ 

CJ 

3 

a 

•H 

Q 

rH 

(fl 

«3 

O 

a 

J 

■H 

U     • 

H 

01 

ft 

o 

■H 

UH 
■H 

■P    >, 

rH 

^ 

CO 

1 

o 

CO 

CT>    0) 

p 

P 

B 

1 

•H 

M 

C3  P 

0>    >, 

•H 

s 

> 

c 

■H     flj 

0>     1 

id 

CD 

3 

•H 

CU  -H 

X3  P 

ft 

XI 

rH 

— 

UH 

rH 

X>  T3 

(0     CQ 

p 

T3 

•H 

X3 

0> 

P 

>> 

CU 

C 

CO 

^~ 

Si 

rH   'H 

e 

<TJ 

p 

co 

>^ 

G 

>l 

•H    UH 

X* 

n 

X! 

•H 

p 

■H 

X 

0) 
ft 

rH 

C5  -H 

CJ 
X 

UH 

CD 

0 

ft 

m 

■H 

0 

o 

10    G 

P      1     ~ 

<-» 

O 

p 

■p 

ft   UH 

-^ 

•H     O 

O    P   ~ 

•H 

Uh 

1 

p 

X     CO   ~ 

-^ 

P 

CO 

3 

■o 

0 

UH 

0 

_^ 

c 

H 

H 

p  >J 

•H     O 

1      P    P 

"> 

•H 

CU 

0 

■p 

1 

X 

a 

2 

2 

03 

rH    UH    0) 

+J 

rH 

P 

A 

0) 

p 

T3  a 

03         X! 

•P 

•rl 

CO 

X 

cu 

cu 

a 

CO 

^     >»   CO 

0) 

rH 

■H 

•H 

1 

03  P 

p 

>>     1 

0) 

s 

rH 

UH 

3 

S 

•H 

C 

>   rH 

Cn 

-_^ 

O 

CO 

o 

•> 

•H 

X     0)   -H 

fl 

to 

^» 

CJ 

J 

P 

J 

u  c 

0 

P     CJ 

a 

CO 

■H 

CO 

J 

•H 

J 

0>    P 

rH 

ft 

:*  ft 

u 

rH 

•P 

CJ 

o 

03 

o 

AS    CJ 

^-~ 

•H 

1         u 

(0 

•H 

p 

CJ 

— 

0 

Cu 

ft 

fe 

C  P 

^ 

c 

p 

>  x  o 

a 

C 

o 

•H 
0 

^ 

u 

CO 

UH 

CO 

•H 
rH     O 

H 

03 
O 

o>  i   x 
p  >  i 

TJ 

^» 

p 

ft 

P 

0 

p 

XI    -P 

J 

S 

~-- 

ft  0)    C3 

c 

CD 

C3 

p 

•H 

1 

■H 

CQ 

2 

X 

►< 

P    rH 

■H 

N 

o 

Eh 

X 

o 

n3 

p 

03 

0>   P 

■H 

II 

CO 

X    ft  03 

UH 

•H 

W 

(D 

ft 

CO 

ft 

co  a 

rH 

c 

CJ 

p 

1 

CO 

p 

CO 

rH 

•H 

C3    01 

<-» 

XI 

--- 

CD 

o> 

CJ 

>    0) 

tP 

*~. 

cu 

u 

rH 

UH 

rH 

UH 

O  P 

>n 

*-» 

>.XJ 

■H 

0)    CJ 

* 

co 

(0 

0 

0 

0 

^-~ 

0 

6    P 

E-i 

'-. 

P 

p 

0 

P   -H 

a 

01 

P 

g 

UH 

o 

CO 

fc 

0 

H 

P 

P 

ft 

ftrH 

PJ 

rH 

ID 

^~ 

P 

p 

J 

P 

0)    ft  PI 

^^ 

0) 

CO 

X 

>, 

w 

XI 

* 

CO 

g 

ft 

>H 

CO 

C 

w 

CO 

xi  e 

H 

&4 

X 

p 

1 

1 

P 

01     S 

a) 

tt 

05 

CJ 

^ 

0 

E- 

■H 

•H 

CO 

■H 

P   -H 

CQ 

J 

a 

■H 

p 

P   TJ 

CJ    03 

Cn 

2 

•H 

•H 

p 

H 

0 

H 

rH 

a 

rH 

H 

w 

w 

•H 

UH 

co 

CO 

U 

•H     P 

ifl 

H 

P 

rH 

0) 

PI 

r-\ 

J 

« 

CO     CO 

CO 

CO 

CO 

rH 

P 

p 

rH   -O 

>J 

J 

03 

£1 

M 

CO 

-^ 

Ei 

H 

CO 

w 

CO 

•H   -H 

H 

i 

XI 

■H 

•H 

o 

CQ 

> 

1 

a 

CQ 

P 

rH 

I 

P 

> 

1 

UH 

UH 

CJ 

>    P 

(0 

rH 

•H 

rH 

CO 

>H 

H 

C 

id 

fi 

CO    P 

Cu 

rH 

X 

■H 

03    0) 

ft 

rH 

cu 

10 

rH 

Jr,     <0 

P 

9 

CO 

•H 

3 

H 

•H 

•H   -H 

o 

1 

H 

03 

II 

II 

P    0) 

05 

o 

c 

X) 

rH     CJ 

•H 

H 

a 

cr  pi 

a 

X5 

w 

Q 

J 

C 

P 

•O  X! 

—' 

CJ 

a 

0 

P     0 

n) 

w 

> 

0) 

PQ 

P     C 

2 

J 

CQ 

O 

CO 

X 

>1 

>. 

1      CO 

0 

03 

Cn 

P 

0)    tP 

ft 

£ 

1 

0> 

O 

Cn 

p 

1 

■p  — 

p 

Cn 

—   « 

P 

>. 

0) 

ft  * 

i 

J 

o 

2 

g 

UH   ^) 

>i 

■H 

> 

> 

0) 

a) 

>, 

(0    W 

CO 

r-\ 

■P 

0  rH 

UH 

c< 

J 

Eh 

p 

W 

H    P 

Q 

rH 

UH 

cu 

CU 

0)    >, 

rH 

rH 

P    * 

C 

a 

^— 

<H 

aa 

c 

H 

W 

0 

CU 

w 

9 

O 

w* 

p 

p 

X 

J3   rH 

1 

a 

cj  a 

•H 

o 

nj 

* 

2 

CO 

c 

o 

CO 

.»   ••> 

ft 

ft 

ft 

— ' 

CO   rH 

p 

•H    H 

p 

2 

■C 

<—    03 

<D 

O  J 

ID 

o 

T5 

p 

CO 

H 

P 

p 

p 

p 

CJ 

M 

* 

ft  CQ 

r-i 

T3 

0) 

0)   Q 

•H 

J 

X) 

•H 

0 

0 

0 

O    -rt 

•H 

o 

XI 

O 

n 

rH 

*  o 

r— | 

CQ 

Q 

0 

S 

UH 

UH 

UH 

T3    UH 

ft 

> 

05 

.£ 

cu 

0) 

CJ  X 

1 

2 

.£ 

S 

< 

p 

P 

3 

T3 

•H    H 

tr 

K  O 

p 

ft 

0 

J 

p 

(1) 

rH 

O 

rH    W 

p 

Eh 

U 

01 

8 

U 

fc 

a; 

e 

(0 

B  A 

0) 

H 

e 

~^ 

co 

UH 
d) 

> 

Pu 

-  w 

CO 

3 

UH 
01 

rH 

> 

D 

-d 

»•> 

-  Q 

■d 

P 

' — 

^^ 

•• 

•-  *-• 

— ' 

1 12  THE  GRAPH  EXAMPLE  Chapter  5 


^ 

? 

c 

»-» 

j 

•rl 

CO 

4-1 

H 

X 

a 

0) 

P 

1 

2 

0) 

c 

i 

a 

H 

•H 

Eh 

0) 

H 

e 

•p 

ij 

p 

2 

s 

■H 

H 

0 

o 

* 

0) 

H 

<4H 

O 

fa 

H 

w 

*-» 

CO 

-o 

X 

4-1 

H 

0) 

Eh 

a> 

—  > 

to 

CO 

a 

P 

1 

a  os  *    ~ 

3 

W 
1 

to 

z 

H 

a 

0)  o       ~ 

to 

O 

J 

0) 

e  z  os  ~ 

•H 

% 

p 

O    W    fa 

§ 

>H 

•H 

a  h  *  j 

w 

i 

* 

rJ  —  z  w 

1            H    (0 

Oh 

E 

Eh 

H 

Eh 

PS 

o 

a 

ft—  J 

2 

CO 

0) 

■p 

o  e  m  « 

ft  H     1     o 

w 

04 

O 

B 

•H 

Z   rH    H 
0)   H    rtj   PS 

.c  ••  c  w 

CO 

Eh 

fa 

u 

a 

o 

fa 

+ 

0) 

P            0    04 

S 

J 

^» 

■p 

ps  c*  d 

—* 

w 

•H 

1 

•o  w   >>  CO 

I 
Eh 

2 
W 

CO 

X 

01 

«J  fa    0  » 

Eh 

Eh 

PS 

c 

2 

H 

o 

■H 

10      ••    »        p 

CO 

*-* 

rH 

6             Z 

o 

2 

^-~ 

B 

0) 

0)   to  fa   w 

fa 

CO 

o 

fa 

B 

P  2  J  2 

2 

fa 

J 

u 

rt 

•H   W   W     I 

P 

w 

w 

i 

6 
0) 

ype 
E-IT 
ER   S 
TARY 

0 

Eh 

H 

=tt 

CO 

1 

o 

•p 

4H 

j 

--~ 

PS 

a 

-— 

•H 

rH 

B 

j 

2 

o 

0 

4-1 

I 

P  >  K  Z 
H  Z  W 

0> 

< 

w 

CO 

o 

d) 

0) 

CO 

H 

O 

Eh 

B 

M 

c 

=1   En   H   2 

p 

Eh 

H 

1 

•H 

C   H   J   O 

•H 

H 

o 

■o 

a 

rH 

0)  to  ffl  2 

CO 

fa 

5 

0) 

0) 

x 

a  S5    1   » 

to 

z 

1 

<D 

X 

e 

p 

w  w 

<fl 

w 

OS 

P 

m 

•H 

4-1 

<D    to    ^    S 

CO 

fa 

■H 

2 

a 

-^ 

0) 

P  W  2  Q 

p 

X 

1 

u 

-^ 

P 

0) 

Eh   W 

w 

P 

Eh 

a 

4-1 

1 

CO  —  Z 

£ 

CO   CO 

J 

U 

H 

s 

0) 

0) 

a 

P   D          H 

P 

H    D  — 

(0 

01 

p 

U 

0) 

0  O  PS  £ 

•H 

•J  O  — 

p 

w  -» — 

+J 

■H 

1 

•p 

4-1    2    W      1 

o)  <: 

to 

p 

04   Eh  — 

•H 

| 

e 

•H 

1     «    W 

I     I     1 

o 

X 

>H    CO   — 

1 

P 

0) 

P.   U   Z   ^ 

W  U  PS 

sg 

<u 

E<HO, 

0) 

0 

p 

0)    H    H    <jj 

a 

04   H  O 

■.?§ 

c 

03 

•H 

0. 

.*  co  iJ  2 

0) 

>H    CO    CO 

1 

•H 
rH 

c 

P 
P 

*"' 

0) 

ft 

■h  m    i 

p 

•H 

^alg 

Eh 

y 

CO  2  t^ 

H    W    ^ 

«-» 

0 

X 

>, 

ri-2g 

2  —  U 

2 

H 

JtHS 

•H 

0) 

rH 

•p 

X)         HZ 

P 

w 

PS 

—  H     1 

P 

p 

C 

■ — 

Q  Eh   W 

0 

Eh   Q   X 

O 

fa 

W 

O 

«J 

0 

0 

(0   O  H   2 

0 

HO  — 

fa 

K          CO 

3 

0)    P 

u 

4H 

« 

K  ~ 

CO          CD 

u 

3   C 

o 

0) 

■H 

0)   Eh  O 
*   W  Eh 

0> 

0   Eh 

fa 

D        O 

P    B 

•H     0» 

<T5 

u 

«_» 

ft  P  W  Eh 

H 

fa         2 

(0    0) 

•0   -H 

e 

c 

* 

«J   2  W 

& 

C    2    W 

w 

4-1    P 

«     >H 

4-1 

0 

2   fa   CO 

•H    fa    J 

0)   -H 

u  o 

<D 

••  H  — 

•-  w  ~ 

■o 

73 

-  Q 

•- 

—  Q 

Section  5.6 


Problem  Set  #5 


13 


P 

—» 

>  Eh 

,« 

0  fa 

&» 

^-» 

■d  w 

—  -H 

>, 

PI  J 

-.    4» 

-0 

■H      1 

e  x; 

*  fa 

tt)  X) 

—      e 

Q 

■p 

e      o 

C7>  H 

■H     * 

O         P 

PI    CO 

as 

_» 

p      -p 

•H    Z 

w 

c       -»  — 

P  —   0 

P    H 

Eh 

o  —  ~  ~ 

2&* 

—    CO     1 

H 

•H   ,C   4J  -» 

—  -H    Eh  — 

^-> 

-4J+J^^ 

«  -p  i 

—    X    fa  — 

g 

<-»    Ifl   T)     t*  P 

-^    0)  W  — 

>H    *- 

g    P   -H   -H    T3 

.       •> 

e  i  »  fa 

«-"> 

3 

tt)     Pi     £     tt)   -H 

O    4)    CO   O 

X   Eh 

P     tt)    X)    A     » 

^.       . 

■P    P  -^  Eh 

EH 

CO 

■ri    -H           Xt    XI 

X  P 

•P    ft          1 

K 

JH 

£    H 

P      4S 

■O  X!  -P 

O         Eh   W  O 

£3 

CO    O    P   -»  *■» 

tn«w 

X)    tt)  fa  Q 

H 

X 

3     1    -0  X!  X! 

+J  -H    tt) 

ft 

'6MH 

fa 

H     1 

1     W 

_^ 

•h  e  -h  +j  p 

X3    4)    ?    &>  C7> 

4H    P   rH 
0)      ►      « 

0 

p 

O  J  co 
•   co       Z 

,-» 

g£ 

u 

(0  +J  Xt    C    C 

rH   —*  w 

• 

1     H 

<"^ 

co 

tt) 

W  -H           tt)    4) 

•P  X!  >-    I 

x  —  — 

I 

X 

1       1      *    H  H 

/ 

*u  V         E-i 

S-rH 

Eh     I 

c 

e  o)  — 

—  —ft 

tt)   -H    fa    fa 

CO   W 

.-» 

•H 

tt)    Pi           CO    CO 

-    >,    O    P 

rH     »    W    W 

H   Eh   Z 

g 

-«= 

rH 

p  -H    +    3    pi 

S3 

—  TJ    P^X! 

*  as  is 

i 

2   Eh 

A 

e 

•H    iH   —'  -H   -H 

O 

— 

0i 

—    PI   Z   CO 

PS   fa   fa 
fa   fa 

w 

W    H 

£   Eh  -* 

1 

01 

1     —          T3    T3 

■H 

e 

—  —    ft 

•H 

tt)    H  — 

CO 

CO 

W   H  — 

r-f     CO 

p 

tt>        P   (0   nj 

P 

0 

—  e  o    • 

P 

—  ft  J 

fa   «   « 

o 

g 

.-^ 

Eh             6 

Ifl    P 

•H 

S3    S3     P    U     U 

<fl 

p 

—   OP 

» 

6  ft  n  fa 

fa  z  z 

o 

W   £ 

,— 

H    £     0) 

S3     S3 

| 

■h  o  cr 

P 

p 

>***      c 

w 

OK    I   o 

«    H    H 

s 

CO  w 

E-i 

g 

O  P 

O   -H 

0) 

rH   -H     CO     *     * 

S3 

0 

TJ   P    +     X 

o  —  -o 

V  A  T.  fr 

Z    J    J 

H>   Eh 

H 

Eh    Eh  -H 

sa 

S3 

^   jj   ^,  ^,  »_, 

4) 

XI 

-— 

P        fa 

m  cq  m 

O   H 

Eh 

SB   Eh 

•H 

<d 

•H 

1    XI     - 

ft 

O   rH    En     1 

J    i    i 

10 

£ 

E-t 

H 

O  o  e 

^~. 

rH      1 

rH 

co  P  X!  \  \ 

P 

ft 

^      ►          +J 

0   ^3    rH    H   — 

m  £  £ 
i   w  u 

s 

..  pq 

fa 

h  m  id 

fa 

ft    0) 

3   C  P  s.  \ 

0 

0 

•  A 

■P 

-  -H 

0  w 

»      fa 

fa 

fa 

fa    i   p 

Eh 

B 

•H    tt)    tx>  —  ^ 

p 

rS      •              C7> 

» 

?  55 

£   Eh   Eh 

P  Eh 

>H 

J 

O 

1     £  -H 

fa 

»        CO 

e 

•O  -h   P! 

cr 

■O        V  ■* 

.  —  o 

W   H   H 

H 

fa   Eh 

1 

Eh 

2   fa     I 

fa 

0) 

«     P     tt)     X     >, 

4) 

4-1 

P  X!    P 

fa 

**   ^     ^ 

(0     1 

J     1 

s 

w  eh  e 

J 

£ 

P 

P 

P     O    rH    TJ    TJ 

■— 

ft 

O"  4h    Cn 

P    4)   fa 

HEh|h 

4->    W 

W    £ 

u 

i 

Eh   H    0) 

8 

0)    p 

•H 

Ifl 

p    4)  -H      1 

P 

45    ft  O 

C   > 

CO    fa 

Eh 

H     1     P 

Eh 

*     0) 

»_* 

S3 

* 

tt)   rH     P   «- 

4-1 

tn  >,CO 

W    H    H 

•H    H 

— 

Z    i 

H 

Eh 

1     Eh  -H 

s§p 

X 

o 

H 

Eh 
O 

m 

•rl    C 

ft 

tt)     * 
ftp 

4) 

9 

CO 

(Q        .      ►       ^ 

41 

N    J    J 
H    t-i    H 

as 

CO 

2 

1 

Eh 

H 

Eh* 

W  ^  "  *"" 

- 

CO    fa    fa 

CO 

fa   Eh 

D  Eh  O  fa    S 

33 

fa 

XI    rH 

^   tt) 

—* 

' 

—■ 

«—  rH      1 

1     H    H 

co  w 

fa 

CO   O   O 

a 

fa   fa    0  o 

1 

1     XI 

P 

rH 

O    Eh 

Eh    CO   CO 

o 

—  o 

fa  O 

fa    >H     4) 

Jm   Eh    ft 

H 

1 

^ 

s  i 

^ 

-^ 

* 

fa 

W    H    H 

3   CO 

CO 

fa 

fa 

w 

fa- 

-^ 

tt)   s 

CO    CO 

CO   >   > 

ii 

gg 

>* 

Eh 

fa 

Eh  —   >,SC 

as 

Eh 

as 

p  tt> 

•H    +J 

4-1 
•H 

•H     1 
fa 

VC  ^>  b* 

CO 

u 

fr>   tr> 

Eh 

2  « 

fr>  0 

•H 

tt)    fa 

www 

V   ID 

1 

H  -~ 

ElSa 

te 

Q 

H 

ft 

CO  it 

U,    CO    CO 

J3  O 

fa 

Eh 

8 

H 

w 

tt)   Ti- 

r4   Z 

Z    1     1 

P  £ 

w 

a  O 

b*   CO 
fa   CO 

fa 

fa 

O  Eh    tt) 

IS 

as 

ft   S3 

tt)    H 

(BLI 
NKEF 
NKEF 

1 
6  U 

fa 

8 

H  O  -P 
fa  fa  -H 

H 

3 

pq 

m 

>,  tt) 

P     CO 

•«  fa 

0)   H 

H 

CO   < 

n 

o 

P   CO 

J 

_ 

Eh 

M    M 

•riS 

PQ 

1 

Q 

Eh 

fa 
CO 

4H 
•H 

fa    fa 

>1~ 
Pi 

W 

% 

fa 

*■"' 

*"' 

Eh 

flj  Q 

CO 

^ 

M% 

w 

*■"" 

C   Eh 

CO 

p 

•H   W 

D  z 

rH    £ 

o 

O 

m  fa 

2 

o 

14  THE  GRAPH  EXAMPLE  Chapter  5 


,-» 

o  — 

■p  £ 

O  ft 

•H    W 

^^ 

»  J 

Eh 

^-» 

o  w 

V<    H 

i   to 

id 

S| 

i 

2   £ 

w  w 

*s 

Eh 

£   Eh 
1     H 

c               — 

W 

g~ 

<D   }H                Eh 

S§ 

B                   (0 

o  w 

X                H 

Eh  Eh 

W   ft 

%       3 

1     H 

£     1 

££ 

a  o            i 

3   Eh  ~         W 

£§ 

Eh     I 

Eh  —        0. 

H   Eh 

01    D    JH           Jh 

an           Eh 

H 

Eh 

ft     1 

=      H 

O  —  X          I 

SB 

0) 
to  ft 

o  o 

8§ 

•P   «  W  ~  Eh 

—  w 

«UH-H 

ft 

^   Q 

D>HH« 

W  X 

U  U 

•rl    J      1      2    W 

M  O  W  W  ft 
1      1     >   Eh   >i 

Eh 

Eh  Eh 

E3  D 

3  W 

ft 

U 

0)   2 

4)   W   H   H   Eh 

2 

w  a 

(0   (0   Eh            1 

H 

X    0) 

£   W 

0  O  H  w  s 
OOIOP<H 

1 

W   P 

b     £ 

Q 

1     -H 

B  £  SS  £  Eh 
••  W  Eh  H 

SB 

2 
O 

to    1 

1 

o  o 

H 

a  to  i  s  o 

<l)  £  w  w  to 

W 

w  (d 

Eh 

U 

ft    Jh 

O 

P    W   10   Eh   10 

ft 

X  +J 

§ 

•H   Eh   D   H   < 

o 

Eh    X 

H   O     1    — 

ft 

..    0) 

ft 

<7>    1     S   Eh 

I 

a  w  ••  &  w 

2 

B 

•H    >  *      O    A 

gT 

Eh 

T— 

.X  H         W  {m 

ft 

to 

ft 

G   Eh  ft  ft  Eh 

ST 

J 

H 

n 

•H    H    iJ    >H     1 

ft 

J 

to 

rH   tO   W   Eh   S 
£)   2   tO  -'  W 

ft   W 

to 

W 

to 

to 

to 

w 

W                Eh   O 

p 

D  O 

01    to   Q    W    H 

Eh  O 

2 

O 

o 

A     l     2    ft 

U   £ 

w 

£ 

ft 

P  w  w  x  o  w 

to 

7 

ft 

to  tO  Eh  Eh 

•J  % 

Eh 

% 

m  D-   i    W 

W  — 

•P  O        S3  to 

to 

o  s  £  w  — 

0>     1    W  Eh  — 

rH  U  Eh  H 

0)   H   H  «-  Q 

to  to        «-  Z 

■P   ft   Eh   Eh   O 

<W  >-  W   W  — 

0)        to  J 

HQ-- 

I    O  — 

0)   K 

to  Eh  Q 

3  W  2 

O  SS  o 

S  ft  o 

Section  5.6 


Problem  Set  #5 


15 


w 

B 

0) 

^^ 

e 

cu 

■p 

-— 

1 

<-» 

P 

•H 

B 

E 
cu 

•H 

B 

cu 
p 

,_, 

P 

E 

0 

•H 

S 

o* 

— - 

^ 

■H 

0  / 

p 

<N 

-— 

/ 

+» 

p 

ft 

>J 

*-% 

ft  -P 

0 

0 

B 

0 

0 

c 

43 

p 

CN 

3 

0) 

c 

p 

J2 

0 

1 

X 

5 

P 

0 

1 

1 

•H 

E 

B 

— 

■H 

•H 

E 

E 

•p 

0) 

<D 

1 

X 

S 

<D 

-p 

cu 
P 

01 

•P 

(0 

p 

p 

•H 

P 
•H 

p 

X 

£ 

0 

c 

•p 

■H 

•H 

c 

1 

1 

t^. 

■P 

•rl 

G 

1 

I 

0) 

P 

P 

g 

CO 

g 

•H 

<-{ 

a> 

P 

P 

■H 

ES 

13 

en 

1     — 

^ 

•H 

0 

0 

M 

0 

0 

^x 

S 

0,  ~ 

B 

c 

M 

0 

0 

0 

0) 

cu 

w 

p:  e 

cu 

0 

O 

cu 

<D 

ft 

ft 

Eh 

•H     CO 

-p 

•H 

a 

e 

cy 

fh 

K 

H 

rH    -P 

•H 

p 

0* 

K 

CU 

p 

p 

0) 

I 

»      -H 

1 

id 

0) 

p 

p 

•— 

^ 

^ 

a 

t 

— 

—  e 

P. 

p 

""' 

w 

*■* 

t» 

•H 
rH 

H 

Eh 

H 

B    CO 

■rl 

0) 

'4-1 

•H 

Eh 

0)   -P 

iH 

•H 

■H 

~^ 

(0 

H 

+J  -H 

u 

«^ 

10 

•H     1 

CO 

0 

■0 

2 

E 

d 

^» 

B 

C 

W 

Oh 

6   co 

•H 

E 

e 

0) 

10 

(0 

CO   -P 

■o 

0) 

a> 

p 

1 

—                 +J   -H 

« 

p 

-p 

■H 

^^ 

w 

—  ^  — >  -H     1 

h 

•H 

•rl 

>. 

o  en 
■p  D 

as 
w 

Eh 

M  ITEM 
ITEM) 
ITEM) 
-item- 
ypeout 

i 

B 

1 

0) 

■p 

P 

ft 

O 

«-» 

<D 

c 

4H 

Cn 

X* 

^~ 

tn  2 

^ 

-— 

P 

■H 

a> 

•H 

ft  — 

--» 

C     1 

■H 

rH 

i-t 

P 

—  CM 

•H    O 

p 

CO 

i 

w 

Oh 

>H 

Eh 

>. 

■P    H 

^ 

i 

g 

TEM-BOTTO 
[TEM-LEFT 
TEM-RIGHT 
( typeout 
e-item  (t 

CU 

a 

0) 

s 
a> 

E 
0) 

-P 

^       ^ 

•H    < 

.— ~ 

o 

Eh 

•H 

0 

+J 

P 

■H     X 

^    c? 

o  m 

to 

? 

H 

■H 

■H 

•H 

0 

ft      >^ 

a 

s 

^ 

-P 

1 

I 

I 

-— . 

ft<" 

s 

w 

9 

IT3 

o 
-p 

•P 

P 

— 

>. 

<N          CN 

<*H     W 

Eh 

Q 

■<■» 

CO 

-P 

r> 

3 

^« 

ifl 

X           >^ 

•H   Eh 

H 

w 

u 

Eh 

3 

a 

0 

0 

CO 

H 

Oh 

X 

•H 

0) 

p 
c 

•H 

0 

ft 

a> 

<u 

n 

^~ 

C    X 

*            * 

0)     1 

05 

& 

Q 

h  v  h  a  c 

T3 

•H 

ft 

ft 

•H 

0) 

CO    W 

o 

2 

i 

s 

w 

Eh 
H 

TYPEOUT - 
[  TYPEOUT  - 
TYPEOUT - 
ot  ( type 
et*  ((li 

* 

U 

>>  >. 

>! 

-d 

0)    >, 

3    CO 

CJ 

pj 

W 

^ 

M 

0 

•p 

-p 

<ti 

--^ 

>  ft 

t— 

T— 

—    ft  — 

0  D 

§ 

Eh 

o 

-— 

>H 

X  — 

p 

s 

■p 

>, 

>>CN 

E  O 

H 

s 

J 

w 

0)    X 

>>  CO    X 

2 

Eh 

H 

s 

W 

Eh 

H 

Eh 

a  ft  >, 

■p 

0)     1 

CO 

O 

i 

W 
CO 

2 

H 

ft 

>. 

X          <N 

£   Eh 

H 

>H 

Eh 

Q 

v/ 

0) 

ft  ft  X 

+J&J 

1 

W 

W 

O    0) 

4H 

4-1 

E 

O 

1 

§ 

^— 

CO 

Oh 

s 

-          -    CH 

s 

c  c 

U 

CJ 

*     0)    * 

B   W 

s 

CO 

Oh 

* 

X  *  X  "" 

d    -rl 

0) 

CU 

^  +J  ^ 

0)   Oh 

w 

Eh 

S 

*-' 

Eh 

Eh 

+J    rH 

■d  T3 

•P  X 

Eh 

H 

w 

Oh 

W 

A\                   rl 

W 

CO      1 

1    *   + 

•H    Eh 

H 

Eh 

H 

O 

5 

V/ 

Oh 

A\ 

v  A  v    0 

0, 

•H     0 

•0  -P 

^, 

^, 

^  -"  *^ 

q)  a 

CO 

-^ 

^ 

o 

1 

t— 

T— 

ft\ 

A  o 

g 

s 

J 

Eh 

Q 

Q 

0)   +J 

X 

X 

E  \ 

+J  x 

w 

J 

X 

W 

| 

I 

X3    C 

0)  ^ 

Eh 

Eh 

Eh 

§ 

CO 

CO 

■P  -H 

X 

CN 

■p 

S^ 

H 

H 

0 

ft  X 

—  +J 

T3    ft 

--  p 

3     1 

~^ 

v^ 

h 

C 

4H 

iw 

cr 

•P   z 

H 

•H    C 

o 

u 

+J    CO 

0)  5 

8 

<«  d 

CU 

cu 

0)  ^ 

OS  fe 

m 

•O  -0 

rH 

••>  w 

.►  0) 

•-  Q 

.-TJ 

116 


THE  GRAPH  EXAMPLE 


Chapter  5 


11 


IS 

U    W 


o>  < 
p 

o  p 

<i)  2 

rH  W 


fl  w   0> 

•p  m  & 

•rtODJ 
SO    3  W   0,  +J   w 

K   rH    - 

x>  i       j  a  -- 

p    0)     I     < 

ozhehHO 

S    OJ  W  2  W 
0>    I     N    ••   H   W 

Pi  En  -H  *     «-  ~ 

•rl    P   P 

43  O    H 
p  W    O) 

04      > 

4J  5m  -d 
(V         c 

rH    ZP 
01    P 

CO    fa    •• 


«-   CM 
0)    0) 

01    0) 


*-  cn 
0>    0) 

"8S 

a  ps 

0)    0) 


T3  TJ 

H    M 


cn  e 

r-   CN    >,-H 
Oi    0)  M 

^  -^  -o  tj  cn  a 

>  CN    O    O    X    •• 
o    >,  Pi    Pi 

•o  «-  to  e 

a  cn  -o  •o  >>  o>  oi 

•H     X     Pi     Pi  rj    +J 

S       a>  a>  r-  -o  -h 

—  r-    (0    CO    X    Pi     I     <w 
>,^  _  rfl     0)    rH 


CN 


CN 
CN 


—  CN 

a* 

(0  r- 
3    X 

rH 

a  x 

-1 


§* 


rH     X  0) 

0)   «-  TJ 

CO  O 

I     -O  Pi 

5  Pi  I 

Id'ri  m 

MAO 

TJ     i  I 

••     01  CO 

rj  ft) 

OH  t)i 

H   nJ  «0 

«j    >  0) 

^    i  i 

0>  T) 

•O    rH  Pi 

O     ft-H 

J3   -rl  <M 

+J    -P  «-' 

ID    rH 

6  a 


p  >* 

0)  A  Pi  oi        <d 

Pi    i  -h  to  to  P   Pi 

■HIHH  0     a    -H 

rH   >H  I  S   -H     0)     6 

I       I  0)  0»  T3  -H  ^ 

J   TJ  *  P    <fl    H 

*   fi  <  'H    H    O  - 

H     0)  6 CN 

•O   to  ••  >   >   >    X 

..   ..  >  +j  +j  +j 

o  o 

•O  -O  O  Pi 

Pi     Pi  U  -H 

•H   -H  (0  6 

>     *  ••  w 

Pi    Pi 
0)    0* 


Q£ 


01    o 

&s 

p 

I      CO 

B  -H 

0)  43 

P  P 
•H 

I  0> 

II 

U    0) 


Section  5.6  Problem  Set  #5  117 


o 
u 
«} 

to  -> 

"d  ** 

.C  to 

■p  d) 

i  -»  n 

■p  -p  a> 

0)    (U  M 

rH  i-H  •• 

■O   -O  > 

I      ••  O 

a»  -o 
woe 

9  *  * 

■a  -o 

C    C  fi 

3   0)  a» 


Chapter  6 

STREAMS  AND  FILES 


6.1  Streams 

Since  the  mechanics  of  interacting  with  different  kinds  of  peripheral  devices  vary 
widely,  and  are  often  quite  messy,  it  is  desirable  to  shield  programmers  from  having 
to  know  the  details  of  such  operations.  This  shielding  is  accomplished  by  routing 
all  input  and  output  operations  through  streams.  A  stream  is  a  message-receiving 
object  (some  use  the  flavor  system  and  some  do  not).  There  are  different  kinds  of 
streams  for  the  different  kinds  of  peripherals.  All  streams  accept  generic  com- 
mands to  perform  some  operation,  and  take  care  themselves  of  the  details  of  per- 
forming that  operation  on  their  particular  sort  of  device.  This  way,  knowledge 
about  how  to  perform  I/O  operations  is  segregated  into  the  streams  themselves, 
freeing  programs  (and  programmers)  from  the  need  to  understand  the  details  of 
these  operations.  All  a  program  needs  to  know  is  how  to  deal  with  streams;  the 
streams  know  how  to  deal  with  everything  else. 

6.1.1  General  Purpose  Stream  Operations   (3.2,  Volume  5) 

Some  streams  only  handle  input;  some  only  handle  output;  some  do  both.  There  is 
a  small  set  of  basic  operations  that  all  output  streams  are  required  to  handle. 


120  STREAMS  AND  FILES  Chapter  6 


Similarly,  there  is  another  set  that  all  input  streams  are  required  to  handle.  Addi- 
tionally, there  is  a  somewhat  larger  set  that  all  streams  are  guaranteed  to  accept, 
even  though  they  themselves  may  not  handle  them.  This  bit  of  magic  works 
through  the  default  handler.  Whenever  a  stream  receives  a  message  it  has  no 
handler  for,  it  passes  the  message  on  to  the  default  handler.  The  default  handler 
then  tries  to  use  some  combination  of  messages  the  stream  does  handle  to  produce 
the  desired  effect.  For  instance,  the  :tyo  operation  is  required  of  all  output  streams. 
It  outputs  a  single  character.  The  :string-out  operation,  which  outputs  a  string  of 
characters,  is  in  the  set  that  is  guaranteed  via  the  default  handler.  Some  streams 
handle  this  operation  directly;  for  the  ones  that  don't  and  pass  it  on  to  the  default 
handler,  it  achieves  the  same  effect  (albeit  more  slowly)  by  repeatedly  sending  the 
stream  the  :tyo  message. 

Among  the  messages  all  streams  handle  is  :which-operations.  The  list  returned 
includes  only  those  messages  handled  directly  by  the  stream.  Messages  handled  by 
the  default-handler  on  behalf  of  the  stream  will  not  appear  in  the  list. 

Here  are  some  of  the  more  commonly  used  messages  which  are  accepted  by  all 
streams  of  the  appropriate  type  (input  or  output),  possibly  via  the  default  handler. 

:tyo  char 

The  stream  will  output  the  character  char.  For  example,  if  s  is  bound  to  a 
stream,  then  (send  s  :tyo  #\B)  outputs  a  "B"  on  the  stream.  (Recall 
that  "#\"  is  a  reader  macro  that  expands  into  the  fixnum  representation  of 
the  character  code  for  the  given  character.) 

:tyi  &optional  eof 

The  stream  will  input  one  character  and  return  it  (as  a  fixnum).  On  an 
interactive  device  this  is  likely  to  mean  first  waiting  for  input  to  become 
available.  The  optional  eof  argument  tells  the  stream  what  to  do  if  it  gets  to 
the  end  of  the  file  (however  end-of-file  is  defined  for  that  kind  of  stream) .  If 
the  argument  is  not  provided,  or  is  nil,  the  stream  will  return  nil  at  the  end 
of  file.  Otherwise  it  will  signal  an  error,  and  print  out  the  argument  as  the 
error  message.  (This  is  not  the  same  as  the  eof  optional  argument  to  read, 
tyi,  and  related  functions.) 

:untyi  char 

The  stream  will  remember  the  character  char,  and  the  next  time  an  input 
character  is  requested  (presumably  via  :tyi),  the  stream  will  return  char. 
Some  restrictions:  you  are  only  allowed  to  runtyi  one  character  before  doing 
a  :tyi,  and  you  aren't  allowed  to  :untyi  a  different  character  than  the  last 
character  you  read  from  the  stream.    Some  streams  implement  :untyi  by 


Section  6.1  Streams  121 


saving  the  character,  while  others  back  up  the  pointer  into  a  buffer. 

characters 

Returns  t  if  the  stream  is  a  character  stream,  nil  if  it  is  a  binary  stream. 

direction 

Returns  one  of  the  keyword  symbols  :  input,  :  output,  or  :  bidirec- 
tional. 

:listen 

This  is  a  test  to  see  whether  there  is  any  input  waiting  to  be  read.  On  an 
interactive  device,  :listen  returns  non-nil  if  there  are  any  input  characters 
immediately  available,  or  nil  if  there  is  no  immediately  available  input.  On 
a  non-interactive  device,  the  operation  always  returns  non-nil  except  at  end- 
of-file. 

:tyipeek  &optional  eof 

Returns  the  next  character  that  is  about  to  be  read  (without  removing  it 
from  the  input  buffer),  or  nil  if  the  stream  is  at  end-of-file.  The  eof  argu- 
ment is  interpreted  as  for  :tyi.  :tyipeek  is  defined  to  have  the  same  effect  as 
a  :tyi  followed  by  an  runty i  (if  end-of-file  was  not  reached),  meaning  that 
you  may  not  read  some  character,  do  a  :tyipeek  to  look  at  the  next  charac- 
ter, and  then  :untyi  the  original  character. 

:string-out  string  &optional  start  end 

The  characters  of  the  string  are  successively  output  to  the  stream.  Many 
streams  can  perform  this  operation  much  more  efficiently  than  the  equivalent 
sequence  of  :tyo  operations.  If  start  and  end  are  not  supplied,  the  whole 
string  is  output.  Otherwise  a  substring  is  output;  start  is  the  index  of  the 
first  character  to  be  output  (defaulting  to  0),  and  end  is  one  greater  than  the 
index  of  the  last  character  to  be  output  (defaulting  to  the  length  of  the 
string) . 

:string-in  eof-option  string  &optional  start  end 

The  stream  inputs  a  number  of  characters,  reading  them  into  string,  string 
may  be  any  kind  of  array,  not  necessarily  a  string,  which  can  be  very  handy 
for  reading  from  binary  files,  start  and  end  specify  the  substring  to  use, 
defaulting  to  the  entire  string,  eof  specifies  what  to  do  if  end-of-file  is 
encountered  before  reading  the  intended  number  of  characters.  If  nil, 
:string-in  returns  normally  and  sets  the  fill-pointer  of  string  (if  it  has  one)  to 
point  just  beyond  the  last  character  read.  If  non-nil,  the  condition  sys:end- 
of-file  is  signaled,  with  the  value  of  eof&s  the  report  string. 


122  STREAMS  AND  FILES  Chapter  6 


:clear-input 

The  stream  clears  any  buffered  input,  i.e.,  input  sitting  in  its  buffer,  waiting 
to  be  read. 

rclear-output 

The  stream  clears  any  buffered  output. 

:force-output 

This  is  for  output  streams  to  buffered  asynchronous  devices,  such  as  the 
Chaosnet.  Any  buffered  output  is  sent  to  the  device,  rforce-output  returns 
immediately,  without  waiting  for  the  output  to  be  completed.  For  that,  use 
rfinish.  If  a  stream  supports  :force-output,  then  usage  of  :tyo,  :string-out, 
and  the  like,  may  have  no  visible  effect  until  a  :force-output  is  done. 


:  finish 


The  stream  does  a  rforce-output  then  waits  for  the  output  to  complete  before 
returning. 


:close  &optional  mode 

The  stream  is  "closed"  and  no  further  operations  should  be  performed  on  it. 
If  mode  is  :  abort,  and  the  stream  is  outputting  to  a  file,  and  it  has  not 
been  closed  already,  the  stream's  newly-created  file  will  be  deleted,  as 
though  it  had  never  been  opened. 

6.1.2  Special  Purpose  Operations   (3.3,  Volume  5) 

There  are  a  wide  variety  of  operations  particular  to  streams  for  one  or  another  of 
the  peripherals  (files,  Chaosnet,  windows,  etc).  Most  of  these  are  not  handled  by 
the  default  handler,  and  so  would  result  in  an  error  if  sent  to  a  stream  which  does 
not  itself  handle  them.  The  bulk  of  the  special-purpose  operations  are  documented 
along  with  the  type  of  device  they're  intended  to  be  used  with.  Here  are  a  few  of 
the  more  commonly-used  of  these  operations. 

:tyi-no-hang  &optional  eof 

Just  like  :tyi  except  that  if  it  would  be  necessary  to  wait  in  order  to  get  the 
character,  returns  nil  instead. 

:read-cursorpos  &optional  (units    : pixel) 

This  operation  is  supported  by  windows.  It  returns  two  values:  the  current 
x  and  y  coordinates  of  the  cursor.  The  optional  argument  is  a  symbol  indi- 
cating in  what  units  x  and  y  should  be  expressed;  the  symbols  : pixel  and 
:  character  are  understood. 


Section  6.1  Streams  123 


:set-cursorpos  x  y  &optional  (units    :  pixel) 

This  operation  is  supported  by  the  same  streams  that  support  :read- 
cursorpos.  It  sets  the  position  of  the  cursor,  x  and  y  are  like  the  values  of 
:read-cursorpos  and  units  is  the  same  as  the  units  argument  to  tread- 
cursorpos. 

:clear-window     ( :  clear-screen  in  older  code) 

Erases  the  screen  area  on  which  this  stream  displays. 

tread-pointer 

This  operation,  and  the  next,  are  supported  by  streams  to  random-access 
devices,  principally  files.  :read-pointer  returns  the  current  position  within  the 
file,  expressed  in  either  8-bit  or  16-bit  bytes,  depending  on  the  type  of  the 
stream. 

:set- pointer  new -pointer 

Sets  the  reading  position  within  the  file  to  new-pointer,  where  the  units  are 
as  with  :read-pointer.   This  operation  is  for  input  streams  only. 

6.1.3  Standard  Streams   (3.4,  Volume  5) 

There  are  about  half  a  dozen  special  variables  whose  values  are  streams  widely 
used  by  many  system  (as  well  as  user)  functions.   Here  are  some  of  them. 

standard-input 

In  the  normal  Lisp  top-level  loop,  input  is  read  from  standard-input  (i.e., 
whatever  stream  is  the  value  of  standard-input).  Many  input  functions, 
including  tyi  and  read,  take  a  stream  argument  which  defaults  to  standard- 
input. 

standard -output 

Analogous  to  standard-input;  in  the  Lisp  top-level  loop,  output  is  sent  to  the 
stream  which  is  the  value  of  standard-output,  and  many  output  functions, 
including  tyo  and  print,  take  a  stream  argument  which  defaults  to  standard- 
output. 

terminal-io 

The  value  of  terminal-io  is  the  stream  which  connects  to  the  user's  console. 
In  a  process  which  is  running  in  a  window  (keep  in  mind  that  each  process 
has  its  own  binding  stack,  and  thus  can  have  its  own  value  for  a  given  spe- 
cial variable),  the  value  of  terminal-io  is  likely  to  be  that  window.  For 
processes  without  windows,  which  don't  normally  communicate  directly  with 


124  STREAMS  AND  FILES  Chapter  6 


the  user  (like  the  mouse  process),  terminal-io  defaults  to  a  stream  which 
does  not  expect  to  ever  be  used.  If  it  is  used,  perhaps  by  an  error  printout, 
it  turns  into  a  "background"  window  and  requests  the  user's  attention. 

error-output 

The  value  of  error-output  is  a  stream  to  which  error  messages  should  be 
sent.  Normally  this  is  the  same  as  standard-output,  but  standard-output 
might  be  bound  to  a  file  and  error-output  left  pointing  to  the  terminal. 

standard-input,  standard-output  and  error-output  are  initially  bound  to  synonym 
streams  which  pass  all  operations  on  to  the  stream  which  is  the  value  of  terminal- 
io.  That  is,  they  are  bound  to  an  uninterned  symbol  whose  function  definition  is 
forwarded  to  the  value  cell  of  terminal-io.  So  if  terminal-io  is  re-bound  {i.e.,  the 
contents  of  its  value  cell  change)  the  synonym  streams  see  the  new  value. 

User  programs  generally  don't  change  the  value  of  terminal-io.  A  program  which 
wants,  for  example,  to  divert  output  to  a  file  should  do  so  by  temporarily  binding 
standard-output;  that  way  error  messages  sent  to  error-output  can  still  get  to  the 
user  by  going  through  terminal-io,  which  is  usually  what  is  desired. 

6.1.4  Making  Your  Own  Streams   (3.5,  Volume  5) 

While  most  streams  are  actually  instances  of  some  flavor,  and  handle  their  mes- 
sages through  the  usual  message-handling  mechanism  of  calling  the  appropriate 
method,  all  that's  really  needed  for  a  simple  stream  is  a  function  which  dispatches 
off  its  first  argument  (the  operation)  and  calls  the  default  handler  if  it  doesn't 
recognize  the  operation.  Here's  a  simple  output  stream,  which  accepts  characters 
and  conses  them  onto  a  list: 

(defvar  the-list  nil) 

(defun  list-output-stream   (op  ^optional   argl   &rest  rest) 
(selectq  op 

(:tyo  (push  argl  the-list)) 
( :which-operations  ' ( :tyo) ) 
( otherwise    ( stream-default-handler 

#' list-output-stream  op  argl   rest)))) 

As  an  output  stream,  the  stream  is  required  to  support  :tyo  directly,  and  to  support 
the  other  standard  output  operations  (like  :string-out)  via  the  default  handler.  The 
default  handler  is  invoked  by  calling  the  function  stream-default-handler,  with  argu- 
ments of  the  stream,  the  operation,  the  first  argument,  and  the  rest  arg. 


Section  6.1  Streams  125 


Here's  a  complementary  input  stream,  which  reads  its  characters  from  a  list. 

(defvar  the-list) 

(defvar  untyied-char  nil) 

(defun  list-input-stream  (op  ^optional  argl  &rest  rest) 
(selectq  op 

( :tyi  (cond  (untyied-char  (progl  untyied-char 

(setq  untyied-char  nil))) 
((null  the-list)  (and  argl  (error  argl))) 
(t  (pop  the-list)))) 
(  :untyi  (setq  untyied-char  argD) 
( :which-operations  ' ( :tyi  runtyi) ) 
( otherwise  ( stream-default-handler 

#' list-input-stream  op  argl  rest)))) 

Note  that  :untyi  must  be  supported,  and  that  the  stream  must  check  for  having 
reached  the  end  of  the  information,  and  do  the  right  thing  with  the  argument  to  the 
:  tyi  operation. 


6.2  Accessing  Files  and  Directories 

Some  of  the  information  in  this  section  will  make  more  sense  after  reading  section 
3,  Pathnames. 

6.2.1  Open,  and  Other  Functions  for  Operating  on  Files  (10,  10.1,  Volume  5) 

All  reading  from  and  writing  to  files  is  done  through  streams.  To  access  a  file  you 
must  have  an  open  stream  to  that  file.  The  fundamental  way  to  obtain  an  open 
stream  to  a  file,  whether  for  reading  or  writing,  is  with  the  open  function. 

open  pathname  &rest  options 

Returns  a  stream  connected  to  the  specified  file,  pathname  may  be  anything 
acceptable  to  fs:parse-pathname,  generally  either  a  string  or  an  actual  path- 
name object,  options  is  a  set  of  alternating  keywords  and  values,  controlling 
such  attributes  of  the  stream  as  whether  it  is  for  input  or  output,  and  how 
many  bits  there  are  per  "character."  Here  are  some  of  the  more  frequently 
used  option  keywords: 

direction 


126  STREAMS  AND  FILES  Chapter  6 


usually  either  :input,  to  read  from  an  existing  file,  or  :output,  to  write 
a  new  file. 

:byte-size 

the  number  of  bits  per  byte;  each  :tyo  or  :tyi  operation  will  deal  with 
this  many  bits  of  the  file.  Note  that  this  need  not  agree  with  what 
the  host  computer  thinks  the  byte-size  for  the  file  is. 

:if -exists     ( Warning:   not  fully  supported  by  Version  8  UNIX.) 

specifies  what  to  do  if  the  :  direction  is  :  output  and  a  file  with 
the  desired  name  already  exists.  Some  of  the  possibilities  are  to  sig- 
nal an  error,  overwrite  the  old  file,  append  to  the  end  of  the  old  file, 
or  write  a  file  with  a  unique  version  number. 

Most  programs  do  not  call  open  directly.  They  more  commonly  use  the  with-open- 
file  macro,  which  makes  use  of  an  unwind-protect  to  guarantee  that  the  stream  will 
be  closed  when  you're  done  with  it.  If  you  call  open  directly,  you  should  also  use 
an  unwind-protect  to  make  sure  the  stream  gets  closed,  because  leaving  around  lots 
of  open  streams  can  create  problems. 

with-open-file  (stream  pathname  options...)  body... 

Evaluates  the  body  forms  with  the  variable  stream  bound  to  a  stream  open 
for  reading  or  writing  to  the  file  specified  by  pathname,  pathname  and 
options  are  interpreted  as  in  open.  When  control  leaves  the  body,  either  nor- 
mally or  abnormally,  the  file  is  closed.  If  a  new  output  file  is  being  written, 
and  control  leaves  abnormally  (i.e.,  because  of  an  error  or  a  throw),  the  file 
is  aborted. 

So  if  I  wanted  to  write  a  new  text  file  in  my  directory  on  the  UNIX  host  sola,  which 
contained  only  the  string  "Wow.  I'm  on  a  disk!"  (without  the  double  quotes),  I 
would  evaluate: 

(with-open-file    (str    "s : //usr//hjb//yippee"    rdirection    routput) 
(send   str    :string-out    "Wow.      I'm  on  a  disk")) 

Or  if  I  wanted  to  see  how  many  characters  into  a  certain  file  the  first  "a"  occurred, 

(with-open-file    (str    "s : //usr//hjb//.prof ile"    :direction    :input) 
( loop   for    i    from    1 

for   char   =    (send   str    :tyi) 

when    (char-equal   char  #\a)    return   i)) 


Section  6.2  Accessing  Files  and  Directories  127 


Here  are  some  more  functions  for  operating  on  files.  They  generally  accept  either  a 
string  or  a  pathname  object,  and  some  of  them  also  accept  a  stream  open  to  the 
appropriate  file. 

renamef  file  new-name  &optional  (error-p  t) 

Changes  the  name  of  the  file.  Meta-X  Rename  File  in  the  editor  uses  this 
function.  If  an  error  occurs  and  error-p  is  non-nil,  the  error  is  signaled.  If 
there's  an  error  and  error-p  is  nil,  the  error  object  is  returned.  See  the 
documentation  for  details  on  what  happens  with  wildcard  names  and  links. 

deletef  file  &optional  (error-p  t) 

The  specified  file  is  deleted,   error-p  is  as  in  renamef. 

fsrfile-properties  pathname  &optional  (error-p  t) 

Returns  a  disembodied  property  list  describing  the  file.  The  car  of  the  list  is 
a  pathname  for  the  file's  truename,  the  rest  is  alternating  indicators  and 
values.  See  the  documentation  for  fs:directory-Iist  for  a  list  of  the  possible 
indicators. 

fs:  change-file -properties  pathname  error-p  &rest  properties 

The  properties  arguments  are  alternating  keywords  and  values.  fs:change- 
file-properties  alters  the  attributes  of  the  file  accordingly,  if  possible.  (Some 
properties  are  not  alterable.  Which  ones  are  is  a  property  of  the  host  file 
system.) 

viewf  pathname  &optional  (stream  standard-output)  leader 

Prints  the  file  on  stream.  (Use  this  just  for  looking  at  a  file,  not  for  copying 
it.   Its  output  is  not  exactly  the  same  as  the  contents  of  the  file.) 

copy f  from-path  to-path  &key  (characters  :default>  (byte-size  niU 

(copy -creation-date  t)  (copy -author  t) 
(report -stream  niU  (create -directories  :query>) 

Copies  one  file  to  another.    M-x  Copy  File  in  the  editor  uses  this  function. 

See  the  documentation  for  the  details  of  merging,  wildcard  names,  and  links, 

and  for  the  meanings  of  the  keyword  arguments. 

probef  pathname 

If  the  specified  file  exists,  returns  a  pathname  for  its  truename.  Returns  nil 
if  the  file  does  not  exist. 

load  pathname  &optional  pkg  nonexistent -ok -flag  dont -set -default -p  no-msg-p 

Loads  the  specified  file  into  the  Lisp  environment.    (If  it's  a  text  file,  load 


128  STREAMS  AND  FILES  Chapter  6 


calls  readfile;  if  it's  a  binary  (compiled)  file,  load  calls  fasload.) 

6.2.2  Special  Messages  for  File  Streams   (10.3,  Volume  5) 

These  are  some  of  the  operations  handled  by  streams  connected  to  files,  in  addition 
to  the  general  operations  described  earlier. 

:pathname 

Returns  the  pathname  that  was  opened  to  get  this  stream.  This  may  differ 
from  the  original  argument  to  open  because  parts  of  the  pathname  may  have 
been  filled  in  with  defaults. 

:truename 

Returns  the  pathname  of  the  file  actually  open  on  this  stream.  This  may 
differ  from  what  :pathname  returns  because  of  links,  logical  devices,  mapping 
of  the  "newest"  version  onto  a  specific  version  number,  and  so  on. 

:length 

Returns  the  length  of  the  file,  in  bytes.  The  number  of  bits  in  each  byte 
depends  on  how  the  file  was  opened.    (See  the  :byte-size  option  to  open.) 

:creation-date 

Returns  the  creation-date  of  the  file,  expressed  in  lisp  machine  "universal 
time"  units  (see  "Dates  and  Times,"  Part  VI  of  Volume  7). 

6.2.3  Directories   (11.1,  Volume  5) 

fs:directory-list  pathname  &rest  options 

pathname  may  be  either  a  string  or  a  pathname  object.  fs:directory-list 
finds  all  files  matching  pathname  and  for  each  one  gets  the  information  that 
would  be  returned  by  fs:file-properties  for  that  file.  It  collects  all  of  these 
into  a  list,  and  adds  one  element  to  the  beginning  of  the  list  with  information 
about  the  file  system  as  a  whole.  So  the  returned  list  has  one  more  element 
than  the  number  of  files.  See  the  documentation  for  a  description  of  the 
options  and  more  details  on  what  information  is  provided  for  each  file. 

fs:complete-pathname  defaults  string  type  version  &rest  options 

string  is  a  partially  specified  file  name.  fs:complete-pathname  looks  in  the 
file  system  on  the  appropriate  host  and  returns  a  new,  possibly  more  specific, 
string.  Any  unambiguous  abbreviations  are  expanded  out  in  a  host- 
dependent  fashion.  There  are  four  full  pages  of  documentation  attempting 
to  explain  how  this  happens  (repeated  in  12.7).   Help  yourself. 


Section  6.2  Accessing  Files  and  Directories  129 


6.3  Pathnames 

6.3.1  General    (12.1,  Volume  5) 

Just  as  streams  are  intended  to  provide  a  uniform,  device-independent  interface 
between  programs  and  the  different  kinds  of  peripherals,  pathnames  are  intended  to 
provide  a  uniform  interface  between  programs  and  remote  file  systems.  The  idea  is 
to  free  the  programmer  from  having  to  keep  in  mind  the  format  for  file  names  on 
the  various  remote  hosts.  With  pathnames,  you  should  be  able  to  manipulate  files 
on  a  file  server  without  knowing  anything  about  that  server's  syntax  for  file  names. 

All  pathnames  are  instances  of  some  flavor,  and  all  the  pathname  flavors  are  built 
on  the  flavor  fs:pathname.  Each  pathname  has  six  components  which  correspond  to 
different  parts  of  a  file  name.  The  mapping  of  the  components  into  the  parts  of  the 
file  names  is  done  by  the  pathname  software,  and  is  specific  to  each  kind  of  host  the 
software  knows  about. 

The  six  components  of  a  pathname  are  the  host,  the  device,  the  directory,  the 
name,  the  type,  and  the  version.  So,  for  example,  the  pathname  corresponding  to 
the  file  /usr/hjb/mbox  on  the  UNIX  host  sola  is  an  instance  of  flavor  fs:unix- 
pathname  which  prints  as  #<UNIX-PATHNAME  "S:  //usr//hjb//mbox">.  It 
has  a  host  of  sola,  a  directory  of  /usr/hjb,  a  name  of  mbox,  and  a  value  of 
:unspecific  for  device,  type  and  version.  The  pathname  corresponding  to  the 
file  >sys>site>notice.text.8  on  the  lisp  machine  glengarioch  has  a  host  of  glen- 
garioch,  a  directory  of  >sys>site>,  a  name  of  notice,  a  type  of  text,  a  version  of 
8,  and    :unspecific  again  for  device. 

A  pathname  need  not  refer  to  a  specific  file.  #<UNIX-PATHNAME  "S:  ">  is  a 
perfectly  legitimate  pathname,  even  though  it  specifies  only  a  host  and  nothing  else. 

The  conversion  of  a  string  into  a  pathname  is  usually  done  by  the  function 
fs:parse-pathname  The  first  thing  it  has  to  do  is  determine  the  host,  since  the 
method  for  parsing  the  rest  of  the  components  depends  on  which  host  it  is.  If  there 
are  any  colons  in  the  input  string,  everything  appearing  before  the  first  colon  is  con- 
sidered to  be  the  name  of  the  host.  Parsing  of  the  remainder  proceeds  according  to 
the  type  of  the  host,  and  its  own  syntax  for  file  names.  (If  there  are  no  colons, 
some  default  value  is  used  for  the  host  —  every  pathname  must  have  a  host.) 

Of  course,  there's  no  need  to  go  through  strings  (and  worry  about  the  remote  host's 
file  name  syntax)  at  all.  One  of  the  selling  points  of  pathnames  is  precisely  that 
you  shouldn't  need  to  do  so.  Accordingly,  one  may  construct  pathnames  in  this 
manner: 


130  STREAMS  AND  FILES  Chapter  6 


(f s :make- pathname  :host  "s"  : directory  ' ( "USR"  "HJB" ) 
:name  "MBOX"  :type  runspecific) 

which  returns  the  same  pathname  whose  printed  representation  was  shown  above. 

Pathnames  are  interned,  just  like  symbols,  meaning  that  there  is  never  more  than 
one  pathname  with  the  same  set  of  component  values.  The  main  reason  for  main- 
taining uniqueness  among  pathnames  is  that  they  have  property  lists,  and  it's  desir- 
able for  two  pathnames  that  look  the  same  to  have  the  same  property  lists. 

6.3.2  Component  Values    (12.1.4,  12.1.5,  Volume  5) 

The  host  component  is  always  a  host  object  (an  instance  of  some  flavor  built  on 
net:basic-host) .  The  permissible  values  for  the  other  components  depends  to  some 
extent  on  the  type  of  the  host,  but  there  are  some  general  conventions. 

The  type  is  always  either  a  string,  or  one  of  the  symbols  nil,  :unspecific  or 
:wild.  Both  nil  and  :unspecific  denote  a  missing  component.  The 
difference  is  in  what  happens  during  merging  (see  below);  nil  generally  means  to 
use  the  default,  and  runspecific  generally  means  to  keep  that  component 
empty.  The  symbol  :wild  is  sometimes  used  in  pathnames  given  to  fsrdirectory- 
list,  and  matches  all  possible  values. 

The  type  field  gives  an  indication  of  what  sort  of  stuff  is  in  the  file.  Lisp  source 
files,  for  instance,  usually  have  a  type  component  of  "lisp,"  and  compiled  lisp  code 
a  type  component  of  "bin."  Since  there  are  some  system-dependent  restrictions  on 
how  many  characters  may  appear  in  this  field,  a  canonical  type  mechanism  exists  to 
allow  processing  of  file  types  in  a  system-independent  fashion.  I  quote:  "A  canoni- 
cal type  is  a  system-independent  keyword  symbol  representing  the  conceptual  type 
of  a  file.  For  instance,  a  Lisp  source  file  on  a  VMS*  system  will  have  a  file  type  of 
'LSP,'  and  one  on  a  UNIX  system  will  have  a  file  type  of  '1.'  When  we  ask  path- 
names of  either  of  these  natures  for  their  canonical  type,  we  receive  the  keyword 
symbol    :lisp." 

The  version  is  either  a  number  or  one  of  the  symbols  nil,  runspecific, 
:wild,  :  newest  or  :  oldest.  The  first  three  have  the  same  meaning  as  for 
type.  : newest  refers  to  the  largest  version  number  that  exists  when  reading  a 
file,  or  one  greater  than  that  number  when  writing  a  new  file.  :  oldest  refers  to 
the  smallest  version  number  that  exists. 


VMS  is  a  trademark  of  Digital  Equipment  Corporation. 


Section  6.3  Pathnames  131 


The  device  component  may  be  either  nil  or  runspecif ic,  or  a  string  designat- 
ing some  device,  for  those  file  systems  that  support  such  a  notion  (VMS,  TOPS-20, 
ITS). 

The  name  component  may  be  nil ,    :wild  or  a  string. 

The  directory  component  may  be  nil  or  :wild  for  any  type  of  host.  On  non- 
hierarchical  file  systems,  a  string  is  used  to  specify  a  particular  directory.  On 
hierarchical  systems,  the  directory  component  (when  not  nil  or  :wild)  is  a  list 
of  directory  level  components.  These  are  themselves  usually  strings.  So  the  path- 
name #<UNIX-PATHNAME  "S:  //usr//h jb//mbox">  has  for  its  directory 
component  the  list  (  "USR"  "HJB"  ).  The  directory  level  components  can  also  be 
special  symbols,  as  well  as  strings.  :root,  for  instance,  refers  to  the  root  direc- 
tory on  the  given  host.  And  :  relative  followed  by  one  or  more  occurrences  of 
:up  refers  to  a  relative  pathname.  So  the  UNIX  pathname  #<UNIX-PATHNAME 
"S:  .  .//foo//bar">  has  a  directory  component  of  (:relative  :up 
"FOO").  And  the  lisp  machine  pathname  #<LMFS- PATHNAME 
"G:<<x>y>z.  lisp">  has  a  directory  component  of  (: RELATIVE  :UP  :UP 
"X"  "Y"  ).  Other  possibilities  for  directory  level  components  are  :wild  (for  any 
single  directory),  : wild-inferiors  (for  any  number  of  directory  levels),  and 
partially  wild  strings,  like    "FOO*". 

6.3.3  Case  in  Pathnames   (12.1.7,  Volume  5) 

Since  the  various  host  systems  have  different  conventions  as  to  upper  and  lower 
case  characters  in  file  names,  most  pathname  functions  perform  some  standardiza- 
tion of  case  to  facilitate  manipulating  pathnames  in  a  host-independent  manner. 
There  are  two  representations  for  any  given  component  value,  one  in  raw  case  and 
one  in  interchange  case.  Raw  case  representation,  which  is  used  internally  for  the 
instance  variables  of  pathnames,  corresponds  exactly  to  what  would  be  sent  to  the 
remote  machine  to  find  the  file  corresponding  to  the  pathname.  Interchange  case  is 
the  standardized  form,  and  is  what  you  get  if  you  ask  a  pathname  for  its  com- 
ponent values.  It's  also  what  functions  like  fs:make-pathname  expect  (unless  you 
specify  that  you  mean  raw  case). 

The  standardization  is  simple.  Each  host  is  classified  as  to  whether  its  preferred 
case,  or  system  default  case,  is  upper  or  lower.  Any  raw  component  which  is  in  the 
preferred  case  for  its  host  has  an  upper  case  interchange  form.  A  raw  component 
which  is  in  the  non-preferred  case  has  a  lower  case  interchange  form.  A  raw  com- 
ponent in  mixed  case  has  an  identical  (mixed  case)  interchange  form.  Since  UNIX 
hosts  are  classified  as  having  lower  case  for  the  system  default,  this  means  that  the 
raw  forms  are  case-inverted  to  get  the  interchange  forms,  and  vice  versa. 


132  STREAMS  AND  FILES  Chapter  6 


The  messages  for  accessing  and  setting  the  component  values  of  pathnames  assume 
that  you  want  to  see  or  set  the  interchange  form,  unless  you  explicitly  specify  raw 
case. 

6.3.4  Defaults  and  Merging   (12.2,  Volume  5) 

In  most  situations  where  the  user  is  expected  to  type  in  a  pathname,  some  default 
pathname  is  displayed,  from  which  the  values  of  components  not  specified  by  the 
user  may  be  taken.  Most  programs  maintain  their  own  default  pathnames,  contain- 
ing component  values  that  would  be  reasonable  in  the  particular  context.  For  pro- 
grams which  really  have  no  idea  of  what  sort  of  pathname  to  expect,  there  is  a  set 
of  default  defaults. 

The  pathname  provided  by  the  user  (actually,  the  pathname  constructed  by 
fs:parse-pathname  from  the  string  provided  by  the  user)  and  the  default  pathname 
are  then  merged  by  the  function  fs:merge-pathnames.  The  details  are  a  little 
messy,  but  the  basic  idea  is  that  components  which  aren't  specified  in  the  user's 
pathname  are  taken  from  the  default. 

6.3.5  Pathname  Functions  and  Messages   (12.7,  12.8,  Volume  5) 

We've  already  seen  three  of  the  most  important  pathname  functions:  fsrparse- 
pathname,  fs:merge-pathnames,  and  fs:complete-pathname.   Here  are  some  more. 

fs: make-pathname  &rest  options 

The  options  are  alternating  keywords  and  values,  specifying  the  components 
of  the  pathname.  Missing  components  default  to  nil,  except  the  host, 
which  is  required.  Options  allowed  are  :host,  : device,  : direc- 
tory, :name,  :type,  : version,  : raw-device,  :  raw- 
directory,  : raw-name,  : raw- type  and  : canonical-type.  So 
the  device,  directory,  name  and  type  may  be  given  in  either  interchange  case 
or  raw  case,  and  the  type  may  also  be  given  in  canonical  form. 

fs:define-canonical-type  canonical -type  default  &body  specs 

This  defines  a  new  canonical  type,  canonical -type  is  the  symbol  for  the  new 
type,  the  body  is  a  list  of  specs  giving  the  surface  type  corresponding  to  this 
canonical  type  for  various  hosts,  default  is  the  surface  type  for  any  hosts 
not  mentioned  in  the  body.  Here  is  how  the  :lisp  canonical  type  is 
defined: 


(f s:def ine-canonical-type  :lisp  "LISP' 
((:tops-20  :tenex)  "LISP"  "LSP") 


Section  6.3  Pathnames  133 


( :unix    "L"    "LISP" ) 
( :vms    "LSP") ) 

The  :host  message  to  pathnames  returns  the  host  component,  which  will  always  be 
an  instance  of  some  flavor  built  on  net:basic-host.  The  messages  :device,  directory, 
.name,  and  :type  return  the  corresponding  component  value,  with  any  strings  given 
in  interchange  case.  The  messages  :raw-device,  :raw-directory,  :raw-name,  and 
:raw-type  are  similar,  but  use  raw  case  for  all  strings.  The  :version  message  returns 
the  version  (case  is  not  an  issue  since  versions  are  never  strings).  The  :canonical- 
type  message  returns  two  values;  together  they  indicate  the  type  component  of  the 
pathname,  and  what  canonical  type  —  if  any  —  it  corresponds  to.  (See  the  docu- 
mentation for  details.) 

The  messages  :new-device,  :new-directory,  :new-name,  and  :new-type  all  take  one 
argument  and  return  a  new  pathname  which  is  just  like  the  one  that  received  the 
message  except  that  the  value  of  the  specified  component  will  be  changed.  The 
argument  is  interpreted  as  being  in  interchange  case.  You  can  guess  what  :new- 
raw-device,  :new-raw-directory,  :new-raw-name  and  :new-raw-type  do.  :new-version 
and  :new-canonical-type  also  do  the  obvious  thing,  and  have  no  "raw"  form  for  the 
obvious  reasons. 

:new -pathname  allows  wholesale  replacement  of  component  values;  its  arguments 
are  alternating  keywords  and  values,  with  the  same  keywords  accepted  as  by 
fs:make-pathname. 

There  are  a  set  of  messages  for  getting  strings  that  describe  the  pathname.  The 
returned  strings  come  in  different  forms  for  different  purposes.  :string-for-printing 
returns  the  string  that  you  see  inside  the  printed  representation  of  a  pathname. 
:string-for-host  shows  the  file  name  (not  including  the  host)  the  way  the  host  file 
system  likes  to  see  it.   There  are  several  others. 

:get,  rputprop,  :remprop  and  :plist  all  do  the  obvious  thing  with  the  pathname's 
property-list.  Keep  in  mind  the  distinction  between  the  pathname's  property-list 
and  the  list  returned  by  fs:file-properties,  or  the  :pro  per  ties  message  to  pathnames. 
The  latter  are  the  properties  of  a  file,  and  require  accessing  the  host's  file  system. 
The  former  are  the  properties  of  a  pathname,  a  lisp  object  which  may  not  even 
correspond  to  any  files. 

6.3.6  Logical  Pathnames   (12.9.10,  Volume  5) 

There  are  some  pathnames  which  don't  correspond  to  any  particular  file  server,  but 
rather  to  files  on  a  logical*    host.    The  logical  host  may  then  be  mapped  onto  any 


134  STREAMS  AND  FILES  Chapter  6 


physical  host,  thus  defining  a  translation  from  logical  pathnames  to  physical  path- 
names. This  feature  improves  transportability  of  code.  Take  the  lisp  machine  sys- 
tem software  as  an  example.  Every  lisp  machine  site  keeps  the  source  code  on  a 
different  computer.  But  there  are  many  functions  that  want  to  be  able  to  find  these 
files,  no  matter  what  site  they're  running  at.  The  solution  is  to  use  logical  path- 
names: all  the  system  software  is  in  files  on  the  logical  host  "sys."  Each  site  gives 
the  "sys"  host  an  appropriate  physical  host,  and  then  it  works  just  fine  to  open  a 
file  with  a  name  like  "sys:  io;  pathnm.lisp,"  which  happens  to  be  the  file  containing 
the  pathname  code.  At  my  site  that  corresponds  to  the  file  ">sys-6>io> 
pathnm.lisp"  on  the  lisp  machine  laphroaig. 

The  function  fs:set-logical-pathname-host  defines  the  mapping  of  file  names  from  a 
logical  host  to  the  corresponding  physical  host.  The  call  to  fs:set-logical-pathname- 
host  is  supposed  to  be  placed  in  the  file  "sys:  site;  host. translations."  Then  if  you 
call  the  function  fs:make-logical-pathname-host  with  an  argument  of  the  host  name, 
it  will  look  for  and  load  the  appropriate  file,  thus  evaluating  the  fs:set-logical- 
pathname-host.  The  format  of  the  arguments  to  fs:set-logical-pathname-host  is  best 
explained  by  example.  This  is  an  abridged  version  of  the  contents  of  "sys:  site; 
kwc. translations,"  which  defines  the  "kwc"  logical  host: 

( f s : set-logical-pathname-host 
"  kwc  " 

: physical-host    "Sola" 
translations 

' ( ( "distribution; "  M//lispm//kwc//rel6//distribution//" ) 

( "distribution;*; "  "//lispm//kwc//rel6//distribution//*//" ) 
( "distribution;*;*; "  "//lispm//kwc//rel6//distribution//*//*//" ) 
("*;"  "//lispm//kwc//rel6//*//") ) 
: rules 

mix 

'  : new-pathname  :name  "PUBSYS") 
:new-pathname  :name  "INPUT-ED") 
'  :new-pathname  :name  "COMTAB-EX") 
.*"  :new-pathname  :name  "CALL-MINI") 
: new-pathname  :name  "MVG-ICONS" ) ) ) ) 

As  you  can  see,  the  mapping  is  done  on  a  directory-by-directory  basis.  Wild-cards 
are  allowed.  For  instance,  files  in  the  directory  "kwc:  distribution;  new-class"  are 
mapped  to  the  directory  "/lispm/kwc/rel6/distribution/new-class/"  by  the  second 
entry  in  the     : translations  argument.    The    :  rules  argument  allows  us  to 


' ( ( : unix 

( "kwc : 

:** 

; public-systems . * 

( "kwc: 

:** 

; input-editor . * . * 

( "kwc : 

:•• 

; comtab-example . * 

("kwc: 

:** 

; call-mini-buffer 

( "kwc : 

:** 

; moving- icons. *. * 

See  hacker's  definition  at  end  of  chapter. 


Section  6.3  Pathnames  135 


specify  additional  transformations  to  be  carried  out  in  special  cases.  Since  our  ver- 
sion of  UNIX  doesn't  allow  filenames  longer  than  14  characters,  we  take  advantage 
of  this  facility  to  define  shortened  names  for  the  UNIX  physical  filenames 
corresponding  to  logical  pathnames  with  long  names. 

Given  a  pathname  for  some  logical  host,  the  mapping  to  physical  pathname  is  car- 
ried out  by  sending  the  logical  pathname  the  :translated-pathname  message.  An 
earlier  version  of  the  text  for  this  chapter  is  in  a  file  whose  logical  pathname  is 

#<LOGICAL- PATHNAME  "KWC:  DISTRIBUTION;  NEW-CLASS;  STREAMS .TALK" >. 
When  that  pathname  is  sent  the  :  trans lated-pathname  message,  it  returns 
#<UNIX-PATHNAME  "S : //lispm//kwc//rel6//distribution//new-class// 

streams .  talk"  >. 


6.4  Fun  and  Games 

From  The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  al: 

LOGICAL  adjective. 

Conventional;  assumed  for  the  sake  of  exposition  or  convenience;  not  the 
actual  thing  but  in  some  sense  equivalent  to  it;  not  necessarily  corresponding 
to  reality. 

Example:  If  a  person  who  had  long  held  a  certain  post  (for  example,  Les 
Earnest  at  Stanford)  left  and  was  replaced,  the  replacement  would  for  a 
while  be  known  as  the  "logical  Les  Earnest."  Pepsi  might  be  referred  to  as 
"logical  Coke"  (or  vice  versa) . 

At  Stanford,  "logical"  compass  directions  denote  a  coordinate  system  in 
which  "logical  north"  is  toward  San  Francisco,  "logical  south"  is  toward  San 
Jose,  "logical  west"  is  toward  the  ocean,  and  "logical  east"  is  away  from  the 
ocean  —  even  though  logical  north  varies  between  physical  (true)  north  near 
San  Francisco  and  physical  west  near  San  Jose.  The  best  rule  of  thumb 
here  is  that  El  Camino  Real  by  definition  always  runs  logical  north-and- 
south.  In  giving  directions,  one  might  way,  "To  get  to  Rincon  Tarasco  Res- 
taurant, get  onto  EL  CAMINO  BIGNUM  going  logical  north."  Using  the 
word  "logical"  helps  to  prevent  the  recipient  from  worrying  about  the  fact 
that  the  sun  is  setting  almost  directly  in  front  of  him  as  he  travels  "north." 

A  similar  situation  exists  at  MIT.  Route  128  (famous  for  the  electronics 
industries  that  have  grown  up  along  it)  is  a  three-quarters  circle  surrounding 
Boston  at  a  radius  of  ten  miles,  terminating  at  the  coast  line  at  each  end.    It 


136  STREAMS  AND  FILES  Chapter  6 


would  be  most  precise  to  describe  the  two  directions  along  this  highway  as 
being  "clockwise"  and  "counterclockwise,"  but  the  road  signs  all  say  "north" 
and  "south,"  respectively.  A  hacker  would  describe  these  directions  as  "log- 
ical north"  and  "logical  south,"  to  indicate  that  they  are  conventional  direc- 
tions not  corresponding  to  the  usual  convention  for  those  words.  (If  you 
went  logical  south  along  the  entire  length  of  Route  128,  you  would  start  out 
going  northwest,  curve  around  to  the  south,  and  finish  headed  due  east!) 


Section  6.4  Fun  and  Games  137 


6.5  Problem  Set  #6 

Questions 

1.  A.   There  is  a  function  named  print-disk-label  that,  when  called  with  no 

arguments,  prints  on  the  screen  a  listing  of  the  contents  of  the  fep  file 
system.  Find  a  way  to  print  this  listing  to  a  file  instead.  (Hint:  check 
out  the  optional  arguments  to  print-disk-label,  and  use  with-open-file.) 

B.  There's  another  function  named  si:print-login-history  that  prints  a  list 
of  everyone  who  has  logged  in  to  the  local  machine  since  it  was  cold- 
booted  (and  the  contents  of  the  login  history  when  the  world  load  was 
made).  This  one  has  no  optional  argument  for  what  stream  to  do  the 
printing  on  —  it  always  prints  to  standard-output.  How  can  you  get  it 
to  print  the  listing  to  a  file?  (Hint:  make  standard-output  point  to  a 
file.) 

2.  Suppose  there  is  a  file  whose  contents  are  numbers  in  the  range 
-2,147,483,648  <  n  <  2,147,483,647  (32-bit  integers).  How  can  we  read 
the  file  into  an  array  of  fixnums?  It'd  be  convenient  to  open  a  32-bit  stream 
to  the  file  and  just  do  :  tyi's  or  a  :  string-in,  but  most  file  servers  won't 
allow  a  32-bit  stream.  We'll  have  to  use  a  16-bit  stream.  One  strategy  is  to 
read  two  16-bit  bytes  at  a  time  and  build  a  32-bit  number  by  shifting  one 
number  16  bits  and  adding  them  together.  This  will  work,  but  it's  awfully 
slow.  Can  you  think  of  anything  better?  (Hint:  think  about  displaced 
arrays  of  different  types.) 


138  STREAMS  AND  FILES  Chapter  6 


Solutions 

1.  A.  (with-open-f ile  (str  "s://usr//hjb//disk-label" 

: direction  : output) 
(print-disk-label  si : *boot-unit*  str)) 

B.  (with-open-f ile  (standard-output  "s ://usr//hjb//logins" 

: direction  : output) 
(si:print-login-history) ) 

2.  The  slow  way: 

(defun  foo  (file  ^optional  array) 

(with-open-f ile  (str  file  :characters  nil  :byte-size  16.) 
(or  array  ( setq  array 

(make-array  ( //  (send  str  : length)  2)))) 
( loop  for  i  from  0 

for  c1  =  (send  str  :tyi) 
for  c2  =  (send  str  :tyi) 
while  c1 

do  (setf  (aref  array  i)  (+  d  (lsh  c2  16)))) 
array) ) 

The  fast  way: 

(defun  bar  (file  ^.optional  array32  array16) 

(with-open-f ile  (str  file  :characters  nil  :byte-size  16.) 
(or  array32 

(setq  array32  (make-array  (//  (send  str  : length)  2) 

: initial-value  0))) 
(send  str  : string-in  nil 

(or  array16  (make-array  (*  2  (array-length  array32)) 
:type  'art- 16b 
:displaced-to  array32))) 
array32) ) 


Chapter   7 

THE  TREE  EXAMPLE 


This  chapter  is  very  much  like  the  graph  example  two  chapters  back  —  a  later  sec- 
tion contains  a  code  listing,  and  this  one  describes  some  of  the  new  features*  of  the 
code.  Much  of  the  code  was  copied  directly  from  the  graph  example  (with  "graph" 
changed  to  "tree").   The  most  interesting  of  the  new  parts  have  to  do  with  menus. 

Once  again,  if  your  site  has  the  tape  for  this  book,  you  can  load  the  code  by  using 
the  CP  command  Load  System  tree  [or  evaluating  (make-system 
'tree)].  Once  the  code  has  been  read,  start  the  program  by  evaluating  (send 
(tv: make -window    'tree-frame)    : select). 


7.1  The  Nodes  and  Arcs 

•root*  and  *the-real-root* 

These  two  variables  are  declared  at  the  very  beginning  of  the  file.    Rather  than 
keep  a  list  of  all  the  nodes,  as  "graph"  does,  we  simply  keep  track  of  the  root  of  the 


See  hacker's  definition  at  end  of  chapter. 


140  THE  TREE  EXAMPLE  Chapter  7 


tree  and  follow  the  connections  from  there.  The  value  of  *the-real-root*  is  constant 
throughout  the  lifetime  of  a  given  tree.  It  changes  only  when  we  throw  away  the 
tree  to  start  another.  *root*  refers  to  the  node  which  is  displayed  at  the  top  center 
of  the  window.  Initially,  this  is  the  same  as  *the-reaI-root*,  but  you  can  change  it 
to  be  any  arbitrary  node  in  the  tree.  That  way  you  can  move  your  window  around 
over  a  tree  too  large  to  be  viewed  at  once. 

The  node  defflavor 

The  connections  between  nodes  {arcs,  in  "graph")  are  no  longer  real  data  objects. 
Each  node  now  knows  directly  which  other  nodes  it's  connected  to,  instead  of  know- 
ing which  arcs  it's  connected  to.  children  is  a  list  (possibly  empty)  of  the  direct 
inferiors,  and  parent  is  the  superior  (nil  for  the  node  which  is  the  value  of  *the- 
real-root*).  The  x-pos  and  y-pos  instance  variables  have  been  thrown  out,  since 
nodes  no  longer  have  fixed  positions.  Each  parent  determines  where  its  children 
will  be  drawn.  The  space -requirements  instance  variable  somehow  packages  up 
everything  a  node's  parent  needs  to  know  about  the  node  and  its  children  in  order 
to  determine  where  to  draw  it.  The  first  time  this  information  is  requested  it  is 
recursively  calculated,  and  saved  for  future  requests.  The  saved  info  is  flushed 
whenever  something  happens  that  would  invalidate  it  (such  as  a  change  in  the 
number  of  children),  so  that  it  is  recalculated  the  next  time  someone  asks  for  it. 
Consequently,  anyone  needing  the  information  should  use  the  :  get-space- 
requirements  method,  which  calculates  if  necessary,  rather  than  looking  at  the 
instance  variable  directly. 

The    :f  lush-space-requirement  method 

This  method  is  called  whenever  the  space-requirement  info  has  been  invalidated.  It 
sets  the  instance  variable  to  nil,  and  recurses  upward,  because  anytime  a  node's 
space  requirements  change  its  parent's  also  do.  It  gets  called  whenever  the  node's 
label  is  changed,  and  whenever  a  child  is  added  or  removed.  (And  whenever  any  of 
these  things  happens  to  one  of  its  descendants.) 

Fancier  format  directives 

The  format  statement  inside  the  : print- self  method  uses  two  features  you  may 
not  have  seen  before.  "-  {...-}"  is  an  iteration  construct,  which  takes  a  list  as  an 
argument,  and  repeats  the  interior  of  the  {  }'s  until  the  list  elements  are  exhausted. 
"-©[...-]"  checks  the  next  argument,  and  if  it  is  nil,  does  nothing.  If  it  is  non- 
nil,  the  argument  is  not  used  up  but  remains  the  next  one  to  be  processed,  and  the 
interior  of  the  [  ]'s  is  executed. 

The  effect  here  is  to  print  a  list  of  all  the  children  (using    -A  so  that  only  their 


Section  7.1  The  Nodes  and  Arcs  141 


names  are  printed),  with  all  but  the  last  in  the  list  being  followed  by  ";  ".  Both 
-  {  and  -  [  exist  in  several  forms,  with  and  without  :  and/or  @,  allowing  various 
kinds  of  iteration  and  selection. 


Drawing 

The         methods  :  draw-self  -and-children         and  :  get-space- 

requirements  have  all  the  smarts.  It's  complicated,  but  I  don't  think  it's  partic- 
ularly interesting.  I  won't  go  into  it  here  since  there's  little  of  general  value.  Do 
feel  free,  however,  to  look  through  the  code  on  your  own. 


7.2  The  Windows  and  the  Mouse 

As  with  "graph,"  the  first  half  of  the  file  is  adequate  if  you're  willing  to  type  awk- 
ward forms  to  a  lisp  listener.  The  second  half  provides  a  better  user  interface, 
mainly  using  the  mouse. 

The  tree-frame  defBavor 

This  time  we  have  three  panes  instead  of  two.  The  new  one  is  a  command  menu. 
Many  system  utilities  based  on  frames  have  a  command  menu  pane,  including  Peek 
(Select  P),  Zmail  (Select  M),  and  File  System  Maintenance  (Select  F).  Command 
menus  differ  from  other  menus  in  that  they  stay  exposed  indefinitely,  becoming 
active  only  when  you  move  the  mouse  over  them,  and  in  that  they  don't  themselves 
produce  any  action  when  you  choose  an  item,  but  simply  stuff  a  blip  into 
somebody's  io-buffer.  It's  up  to  whoever  reads  from  the  io-buffer  to  do  something 
with  the  blip  (often  sending  it  back  to  the  command  menu  with  an  :  execute 
message) .   There  are  more  details  on  how  menus  work  later  in  the  chapter. 

Shared  io-buffers 

For  the  process  running  in  the  tree  pane  to  see  the  blips  from  the  command  menu, 
the  two  windows  must  share  one  io-buffer.  The  :  after  :  init  method  on  tree- 
frame  arranges  this.  I  could  have  built  tree-frame  on  tv:bordered-constraint-frame- 
with-shared-io-buffer  instead  of  plain  tv:bordered-constraint-frame,  but  then  the  lisp 
pane  would  also  share  the  one  io-buffer,  and  that  wouldn't  work.  (Some  input 
intended  for  the  tree-pane's  process  would  be  read  by  the  lisp-pane's  process,  and 
vice  versa) 

Tree-window's    : main-loop 


142  THE  TREE  EXAMPLE  Chapter  7 


There  are  now  two  kinds  of  blip  to  watch  for:  the  familiar  :  typeout-execute 
blips  from  the  mouse-sensitive  items,  and  new  :menu  blips,  from  the  command 
menu.  For  now,  all  you  need  to  understand  about  the  action  taken  for  :menu 
blips  is  that  the  command-menu  itself  is  sent  an  :  execute  message  with  an  argu- 
ment of  the  menu  item  that  was  chosen. 

Tree-window's    :  refresh 

Drawing  the  tree  is  accomplished  by  sending  : draw-self -and-children  to 
the  current  *root*,  which  will  recursively  send  the  same  message  to  its  descendants. 
The  initial  arguments  put  the  *root*  at  the  top-center  of  the  window. 

The  menu-item-list 

Now  we  get  into  menus.  First  off,  I  should  mention  that  the  documentation  on 
menus  —  Part  III  of  volume  7  —  is  not  too  bad.  (In  fact,  much  of  this  stuff  I  had 
actually  never  messed  with  until  the  day  before  writing  the  first  version  of  this 
chapter.  I  just  read  the  documentation  and  did  it.)  The  basic  idea  is  that  menus 
are  special  kinds  of  windows  that  maintain  a  list  of  items  to  choose  from,  and  do 
something  appropriate  if  you  click  on  one  of  the  items.  The  list  of  items  is  kept  in 
the  instance  variable  item-list;  once  a  menu  has  the  right  item-list,  the  :  choose 
method  does  the  rest:  it  exposes  the  window,  waits  for  you  to  click  on  some  item 
(the  : mouse-buttons  method  tells  it  when  that  has  happened  by  setting  the 
chosen-item  instance  variable),  and  sends  itself  the  :  execute  message  with  an 
argument  of  the  chosen  item.  The  :  execute  message  does  something  appropri- 
ate, depending  on  the  type  of  the  item. 

And  now  for  the  format  of  the  items  on  the  item-list,  and  what  it  means  to  "do 
something  appropriate"  (the  task  of  the  : execute  message).  The  simplest  kind 
of  item  is  just  a  string  or  a  symbol.  The  string  or  symbol  is  displayed  in  the  menu 
as  itself,  and  executing  such  an  item  just  means  to  return  it.  The  item  may  also  be 
a  list  (or  dotted-pair)  of  two  elements;  the  first  is  the  symbol  or  string  to  be 
displayed,  the  second  is  what  is  returned  by  execution  of  the  item.  The  most  gen- 
eral kind  of  item  is  a  list  of  three  or  more  elements.  The  first  is  what  to  display  in 
the  menu,  the  second  is  a  keyword  for  the  type  of  this  item,  the  third  is  an  arbi- 
trary argument  whose  interpretation  depends  on  the  type  of  the  item,  and  the  rest 
of  the  list  is  alternating  pairs  of  modifier  keywords  and  values.  The  keyword  in 
position  two  may  be  any  of:  : VALUE,  :EVAL,  rFUNCALL,  .-FUNCALL- 
WITH-SELF,  : NO-SELECT,  : WINDOW-OP,  :KBD,  :MENU,  or  : BUTTONS. 
The  first  three  are  the  most  commonly  used.  :  VALUE  means  to  return  the  argu- 
ment (the  third  element  of  the  list),  :FUNCALL  means  to  funcall  the  argument 
(presumably  the  name  of  a  function)  and  return  its  return  value,  and  :EVAL 
means  to  evaluate  the  argument  (presumably  a  lisp  form)  and  return  its  return 


Section  7.2  The  Windows  and  the  Mouse  143 


value.  The  only  defined  modifier  keywords  are  :FONT  and  :  DOCUMENTATION. 
:FONT  specifies  which  font  should  be  used  to  display  this  item  in  the  menu, 
:  DOCUMENTATION  is  what  appears  in  the  who-line  when  the  mouse  is  over  this 
item. 

If  you  look  at  the  *tree-command-menu-item-list*,  you'll  see  that  all  three  items  use 
the  general  form.  Two  of  them  are  of  the  rFUNCALL  type  and  one  is  of  the 
:  EVAL  type. 

tv:menu-choose 

The  easiest  way  to  use  menus  is  to  call  the  function  tv:menu-choose  with  an  argu- 
ment of  a  suitable  item-list.  This  function  will  allocate  and  expose  a  menu,  set  its 
item-list  instance  variable  to  be  the  argument  you  supplied,  and  send  it  the 
.•choose  message.  Its  : choose  method  then  waits  for  you  to  click  on  an  item, 
and  sends  the  menu  :  execute  of  the  chosen  item.  If  you  look  at  the  : mouse- 
click  method  for  tree-window,  you'll  see  that  clicking  right  anywhere  except  over 
a  mouse-sensitive  item  does  just  that.  It  calls  tv:menu-choose  with  an  argument  of 
*tree-command-menu-item-list*.  (The  use  of  process-run-function  is  necessary 
because  the  : mouse-click  method  runs  inside  the  mouse  process  —  without  it 
the  mouse  process  would  be  hung  until  tv:menu-choose  returned,  but  tv:menu- 
choose  would  never  return  because  the  mouse  process  is  hung.) 

The  command  menu  revisited 

The  command  menu  pane  uses  exactly  the  same  item-list,  as  you  can  see  from  look- 
ing at  the  tree-frame  defflavor,  in  the  : panes  section.  But  as  I  said  earlier,  com- 
mand menus  work  differently;  you  don't  send  them  the  :  choose  message.  They 
stay  exposed  indefinitely,  and  when  you  click  on  one  of  their  items  they  just  stuff  a 
blip  into  their  own  io-buffer.  In  our  case,  that  means  the  tree  pane's  io-buffer. 
When  the  :main-loop  finds  it  there,  it  sends  the  : execute  message  back  to 
the  command  menu  (with  most  menus  the  :  choose  method  does  this  for  you), 
and  the  chosen  item  is  executed  normally. 


7.3  Fun  and  Games 

From  The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  ah 

FEATURE  noun. 

1.   An  intended  property  or  behavior  (as  of  a  program).    Whether  it  is  good  is 
immaterial. 


144  THE  TREE  EXAMPLE  Chapter  7 


2.  A  good  property  or  behavior  (as  of  a  program).  Whether  it  was  intended  is 
immaterial. 

3.  A  surprising  property  or  behavior;  in  particular,  one  that  is  purposely  incon- 
sistent because  it  works  better  that  way.  For  example,  in  the  EMACS  text 
editor,  the  "transpose  characters"  command  will  exchange  the  two  characters 
on  either  side  of  the  cursor  on  the  screen,  except  when  the  cursor  is  at  the 
end  of  a  line;  in  that  case,  the  two  characters  before  the  cursor  are 
exchanged.  While  this  behavior  is  perhaps  surprising,  and  certainly  incon- 
sistent, it  has  been  found  through  extensive  experimentation  to  be  what  most 
users  want.   The  inconsistency  is  therefore  a  feature  and  not  a  BUG. 

4.  A  property  or  behavior  that  is  gratuitous  or  unnecessary,  though  perhaps 
impressive  or  cute.  For  example,  one  feature  of  the  MACLISP  language  is 
the  ability  to  print  numbers  as  Roman  numerals.  See  BELLS  AND  WHIS- 
TLES. 

5.  A  property  or  behavior  that  was  put  in  to  help  someone  else  but  that  happens 
to  be  in  your  way.  A  standard  joke  is  that  a  bug  can  be  turned  into  a  feature 
simply  by  documenting  it  (then  theoretically  no  one  can  complain  about  it 
because  it's  in  the  manual),  or  even  by  simply  declaring  it  to  be  good. 
"That's  not  a  bug;  it's  a  feature!" 

The  following  list  covers  the  spectrum  of  terms  used  to  rate  programs  or  por- 
tions thereof  (except  for  the  first  two,  which  tend  to  be  applied  more  to 
hardware  or  to  the  SYSTEM,  but  are  included  for  completeness): 


CRASH 

BUG 

CROCK 

WIN 

STOPPAGE 

LOSS 

KLUGE 

FEATURE 

BRAIN  DAMAGE 

MISFEATURE 

HACK 

PERFECTION 

The  last  is  never  actually  attained. 
7.4  The  Program 


Section  7.4 


The  Program 


145 


146 


THE  TREE  EXAMPLE 


Chapter  7 


0) 

,_l 

^x 

0)   43 

CD 

•H 

o> 

0)     <D 

s 

0)  -» 

C 

■O    o 

T3 

•H 

U 

C 

73 

43  73 

Oi    O 

C  +J 

0) 

0    id 

01 

73 

•p 

0 

0 

•d   0 

0)       rl 

0    0^ 

rl 

(3    0)    0> 

01 

<d   ai 

■H 

>, 

rH     C 

rl 

O    rH 

13 

43 

C 

rl    43 

0) 

P 

id 

■P  id 

CO      rl      0) 

r-\ 

CO    >,+J 

0 

-p  <-. 

43 

•H 

rH 

O  >w 

■H          £1 

0) 

•rl 

•H  43 

o)  c 

0)         ^ 

P 

CO 

ft 

c  o 

0  c 

43   oi   id 

T3 

43 

43         4h 

13 

43  W   Oi 

0 

CO 

Xi    -rl 

H->    43    rH 

0 

0 

-P  -0    0 

0    0) 

■P    0    C 

4-1 

ft 

•rl 

£      tH 

•P    Xi 

■P 

C 

0) 

C       rl 

•rl 

0 

73 

4->     0) 

•P 

4H           4-1 

CO 

43    0)    3 

id 

««    X    O 

P 

•H    -p 

C    -H 

O    0>    0 

0) 

p 

CO 

0   id   id 

p 

0 

CO 

S     0) 

■H    > 

rl 

43 

•H 

0     CO 

•H    0) 

e  ft 

0 

0 

•H 

s 

CO  v      fi 

P 

T>    t3 

43      rl 

u         co 

0 

M 

CO   -H 

CO    CO 

rl      0)     -P 

T3 

0>          (V 

■P      0> 

to     0) 

M 

(V 

0       rl 

>  o> 

O    >     C7> 

C 

(3 

T3    0)  43 

43 

•H    43   rH 

c 

0 

73    0 

0  73 

•h       a 

•H 

id 

0)    O   -P 

4-1    -P 

rH    +J     Id 

0) 

•H 

u 

0    ft 

rl       0 

rl    4-1     0) 

0)  (d  ^ 

•H 

O 

fl 

•p 

C 

c 

OI   -H   rH 

Tl 

<D 

(3    ft 

4H 

Id    73   -H 

p 

B 

73 

c 

4H 

0) 

T3 

co  u 

0)   -H 

C    4-» 

a) 

4H      (3 

a)  -p 

CH    C 

fh 

0 

0>           0) 

O 

'-     «3      rl 

p 

0 

43 

0   <d 

o>   c 

•H   -H     O 

<d 

C 

O  H  45 

id  co 

-«           ai 

(d 

43 

■P 

5    0) 

—    C 

id  (d  -P 

ft  C  T3 

0> 

CO 

—  rH 

■P    o 

-'   -P 

ft 

CO 

ft  -P     0> 

CO    0) 

rH    ~ 

rH 

0) 

43 

CO     01 

0)  id 

co         C 

to 

•H 

co  a  oi 

ft 

•H     CO     0> 

a 

u 

>, 

o 

rH    A 

43  n 

Ol   +J    0) 

•H 

43 

0    0 

rH     ft  43     0)     C 

a 

C 

rH 

■H 

0)     Id 

•O 

•O    C  -O 

■d 

P 

rH     N    +J 

(d  <d 

O     C   -H 

id 

id 

P 

43 

X    rH 

co  id 

O    0i    C 

id  -h 

•P  43 

•H     C 

1 

X 

P 

c 

5 

•H 

rH 

C      rl      0> 

<v 

>>  -P 

0 

rH    rH    -H 

IV 

to 

0> 

ft    C 

01     C 

id    ft  43 

43 

coo) 

■P  43 

rH             g 

1 

S3 

H 

c 

0) 

X     0) 

rl      ft     01 

0     43       rl 

O 

(d      0>     rl 

•H 

M 

•H 

C    0) 

■H     d) 

0)         T3 

0  T) 

n      -a 

0)   -H 

e  c  oi 

o 

43 

3 

•H     > 

ft    S 

43    co  -^ 

■p 

a) 

•H    rH    rH 

43  43 

CO   -H    4J 

ft 

0 

5 

>-  4J 

4-> 

■P  » 

■0 

rl      Id     "H 

■P    » 

4->    01 

id 

0 

0 

0 

4-1     0) 

0    0>     CO 

•> 

0) 

0  -P  43 

01    O   73 

u 

-o 

0 

73 

0>   £1 

O  X) 

13    rH 

Cn 

0) 

43    0    O 

6     - 

C    0) 

0 

&> 

0  -d 

c 

N 

4-1     0     0) 

C 

(3 

■p 

0    M 

0      C      rl 

en 

_c 

0 

■H 

•H    CO 

rl       CO 

OCX 

•H 

rH             01 

u    0> 

C    0 

id 

C 

2 

CO   rH 

<U    rH 

■H 

rl 

0) 

id   oi  43 

4H  43 

(0     0    4-1 

OQ 

rl 

01 

43    0) 

■P    CO     ft  -P 

0 

■P  43  -P 

4-» 

id  o  >- 

0 

o; 

<D 

a) 

0)     X 

§    X 

CO   -H 

to 

id 

0  -P 

CO    0) 

43 

.a. 

•H 

A 

43 

43 

43    -H 

3   -H 

•rl    43     C 

ft -p 

rl      t^ 

0)     4H 

Cm 

i-l 

p 

p 

■P 

4->     ft 

C    ft 

rH    4->    -H 

id 

CO 

<4H   rH 

0)    0 

4-1    43    rH 

w 

CO 

u 
id 
o 

oi  o  <d 

43 

■p  -p  >, 

4H    +J 
4H 
•H    4-» 

•H    4->     0) 
CO 
73     Ol 

^. 

CO  43 

73     0 

c  c  o> 

CO 

a) 

•H 

ft 

id  -h   c 

3 

a) 

43 

••   rH   XI 

CO 

>    -rl 

*-»  -H 

0> 

■p 

CO            0> 

•rl     C 

0>  id  73 

4J    73 

<0 

-P   id  -o 

43    0) 

■H      U      rj 

C   id 

M 

CO 

0"    of  0) 

■P      rl 

43    73    rH 

01    u 

o 

id 

T3 

o 

rl 

ID 

e  -p  c 

1    t-* 

C0      rl      C 

<d   C 

& 

a) 

rH 

* 

oi  c 

rH     0)     0) 

•H 
0>  43 

•H     0   -H 

4H 

ft   0) 

rl 

•*> 

>, 

CO 

0)    T3     O 

C    O 

Q)    «_-       - 

rH    73 

(U 

4-> 

3 

C  id 

•H 

73            CO 

0)    rH 

CO 

CO 

•H 

0)     0)     ft  73     CO 

0      Cr 

43  -H 

H 

-0 

>    O    CO 

73    -P 

C  a>  c 

•d  43 

J 

a) 

id 

•H    CO 

Id   -H 

rl    id 

rH     O 

e 

O 

o 

U 

r-i 

4H    0>    0> 

ft 

CO    73   73 

id 

o 

i 

•H 

T3   43 

rH 

•H    rH     C 

CO     CO 

OI 

CO 

*-»  T- 

0 

C 

M-l             H-> 

(0   rH 

43  -H    0) 

01     0) 

"8 

*    — 

o 

TJ 

O    CO 

rj      Id 

4-»    43     O 

r-t    rH 

a) 

CO   CO 

co    * 

O 

CO 

+1    ... 

rH 

U     CO 

43    43 

s 

43 

rH 

3 

Ot 

n 

p 

■P   -H     C 

ft    C 

4-1            to 

id   id 

-P 

•H 

•H     * 

*    (3 

i 

(3 

CO            0> 

id 

•H     d)   73 

•H     -H 

•« 

C 

rH 

73    0) 

0>  -H 

1 

0) 

•H     43      rl 

■P    43 

43 

IH      rl 

a 

c 

■rl 

Id     N 

c  o 

B 

rH    -P    T) 

CO    4-1 

rl    4J    rH 

•d  <d 

CO 

■H 

c 

rl    -rl 

•h  id 

—        B 

0) 

•H   rH 

•H 

0           rH 

>  > 

•H 

P 

1      CO 

O    ft 

r-t            -H 

iH 

Id     »    -H 

rH     0) 

4H    Id 

i     i 

rH 

0 

* 

0)     1 

id  co 

•H    —    (3 

■H 

43 

O 

-  o 

01    0) 

id 

CO 

0 

2 

•o  c 

ft  i 

(3    rH    -rl 

-~* 

0 

CO      rl      O 

co  id 

C           4H 

o  o 

•p 

(V 

i-l 

-^ 

0 

O   -H 

CO    rH 

•H    e 

rH 

cr 

•H     0 

0  ft 

0>  43    0 

c  c 

(V 

0 

rH 

■o 

C     0> 

i    <d 

c  c  * 

■H 

0) 

X!    0) 

0   co 

rl      O 

id  <d 

N 

u 

H 

■H 

c 

1         rl 

rH    +J 

(V 

13 

rl 

CO    -P   43 

•H 

73    (d  -H 

4-1    4-1 

4-1 

id 

C 

■H 

l§ 

Id    a 

rl     -P      CO 

■H    01    -P 

>    0) 

rH    01  -H 

CO     CO 

0) 

» 

O     O 

0> 

TJ    (3    D 

i-H 

01 

43    d 

01       rl 

•H          73 

c  c 

X 

4-1 

H 

* 

e   i 

•H     N 

X) 

H     lid 

0) 

0 

Eh    0  *H 

U    0  43   4H    (d 

•H   -H 

id 

0 

p 

0) 

•H     0) 

-P   -H 

0 

■h  nd 

42 

<d 

■-■  +J    0 

ft  e 

O      O      rl 

1     1 

-p 

>^ 

43 

0 
0 

a) 

rl 

C    73 
■H     O 

U     U 
0)     O 

c 

43    id   id 

t)      ft     rl 

id 

ft 
to 

0)    01 

id 

P 

rl 

■P 

e  c 

>      rH 

rl 

-^ 

•-' 

••>   ••   •••  — » 

—  43  43 

CO 

rH 

* 

* 

* 

*  * 

*     * 

o 

> 

^ 

—  itj  as 

•P    4-1 

1 

CO 

ri 

M 

rl 

u  u 

u   u 

id 

4J    4-1 

•H 

id 

m 

id 

id  <d 

id  id 

rH 

01    ai 

1 

■o 

> 

4-1 

> 

4H 

> 

4H 

>   > 

4H    4H 

>   > 

4-1    4-1 

4H 
4-1 

CO    0^ 

<D 

0> 

0 

0>     0) 

U    01 

01 

!I 

!I 

73 

X3 

•o 

73  -d 

•O  T3 

■o 

Section  7.4  The  Program  147 


♦J 

... 

g 

s 

UH 

i 

p 

•H 

a 

* 

CD 

»-» 

U 

a) 

a 

a) 

<N 

u 

o 

■p 

rH 

CD 

0 

CD 

£1 

c 

--» 

£ 

P 

13 

(0 

c 

rH 

■H 

•H 

CD 

rl 

£1 

Q) 

■d 

P 

P 

rH 

en 

rH 

V 

■H 

c 

CD 

5 

.-» 

ft 

—   43 

a; 

•Q 

<-» 

I 

CU      U 

rH 

1 

<t5 

rH 

V 

to 

>1 

UH 

u 

a,  cd 

Cn 

rH 

p 

•H 

tH  e 

C 

CD 

•H 

c 

fl 

Eh    Iti 

■rl 
P 

5 

1 

CD 

e 

to 

03 

••    C 

P 

<-\ 

CD 

rH 

iB^ 

to 

*H 

•d 

■H 

rl 

CO 

•• 

0 

0) 

■p 

„, 

C 

•H 

CD 

«       « 

* 

A 

(0 

CD 

»-» 

cr 

rl 

Eh    r-> 

s 

P 

0) 

rl 

to 

CD 

0 

to   l 

0 

en 

P 

0 

p 

Sh 

a 

t3 

c 

O 

a 

— » 

C 

i 

Cn 

Pn    •" 

C 

CD 

en 

CD 

CD 

•H 

J  ■-> 

*     * 

•H 

.—* 

H 

co 

■H 

to 

e 

0 

W    @J 

to  a) 

S 

CD 

1 

« 

p 

0 

it) 

s 

CO    I 

3     N 

-^ 

P 

CD 

-— 

C 

rl 

ft 

03 

<-• 

—  < 

•H   -H 

CD 

0 

42 

CD 

CD 

■H 

to 

CD 

—* 

•a  to 

<D 

^-~ 

c 

P 

T> 

r-i 

to 

e 

3 

1 

rl 

—^ 

Eh  — 

It    1 

iH 

* 

en 

0 

CD 

3 

CD 

& 

45 

P 

z 

O    i 

u  c 

-P 

to 

■H 

0 

(3 

X) 

•H 

rl 

CD 

to 

to 

T3 

w  ^ 

0) 

1    -H 

* 

;3 

p 

id 

TJ 

■H 

rl 

0 

CD 

T) 

■d 

at  en 

•H 

*J 

rH 

03 

3 

rH 

rH 

e 

«    t   - 

0 

•d  p 

n 

T3 

to 

en 

1 

rl 

cr 

CD 

■H 

UH 

^^ 

its 

°    ^  ~ 

a 

0    i« 

c 

ffl 

CD 

c 

--~ 

en 

«— « 

P 

I 

CD 

U 

C 

UH 

c 

1    <  — 

a  e 

CD 

P 

u 

•H 

* 

Pi 

CD 

P 

rl 

it) 

rH 

§ 

2    i    -- 

10 

to 

1 

<A 

T3 

* 

■H  ~ 

^- 

to 

CD 

| 

ft 

to 

P 

CD 

9 

B=  g 

0 

i  d 

CD 

u 

0 

c  <^ 

to 

CD 

to 

P 

C 

CO 

•H 

T3 

0 

T3 

P     <P 

to 

CD 

U 

1 

G 

CD 

1 

z  e  a> 

T3 

e  o 

\ 

O 

-~- 

o 

S3 

rH 

<0   rH 

3 

rl 

rl 

it) 

.£ 

CD 

rl 

-p 

rH 

5    03     P 

4 

•H     (3 

V, 

c 

*i 

u 

•H 

•rH 

3     CD 

•H 

CD 

a 

to 

e 

its 

c 

CD 

«  a)  -p 

M 

c  * 

■H 

Its 

^- 

s 

C 

=     m 

«d 

P 

to 

3 

CD 

ft 

•H 

X) 

1      rl     to 

I 

■H 

i 

c 

1 

* 

IH 

* 

rH 

rl 

M 

it) 

O  -P 

4-> 

a  + 

•H 

to 

rH 

CD 

> 

p 

03 

? 

X! 

UH 

•H 

■d 

ftrH 

Z     CO     CD 

0) 

e 

3 

CD 

CD 

UH 

i 

0 

to 

3 

c 

0.H            g 

to 

r-i 

•H 

•H 

43 

P 

•H 

p 

T3 

0 

er  <u 

P 

1     Eh   4-»    US 

CD 

<v 

X 

Pi 

CD 

T3 

Its 

P 

P 

CD 

CD 

(3 

rH 

CD 

0) 

to 

CD 

0 

*»  «  c 

M 

A 

(0 

•H 

T3 

* 

rH 

0 

to 

-a 

•H 

UH 

X} 

rl 

^^ 

T3 

-^ 

uh  h  e 

CO 

03 

e 

s 

0 

U 

c 

0) 

0 

IS 

0 

i 

0 

•H    «    P    O 

"§ 

d 

rH 

* 

c 

P 

P 

rl 

a 

1 

a 

CD 

P 

C 

CD 

43  Cu    0    C 

•H 

CD 

0 

0 

> 

CD 

UH 

U 

c 

s 

(0    ••   UH   -H 

43  d 

UH 

fl 

G 

C 

p 

CD 

rH 

it! 

CD 

03 

fl)    H  w    ^ 

4J 

0 

•H 

T3 

P 

P 

■d 

rl 

CD 

T3 

ft 

M 

X) 

C 

rH    CO            ft 

0 

P 

0 

0 

P 

to 

0 

to 

it) 

0 

to  —         ~- 

S 

cr 

P 
CD 

■d 

A 
P 

T3 

A 
P 

cr 

ft 

p 

■*■* 

UH 

c 

p 

CD 

to 

c 

CD 

T3 

C 

CD 

p 

■d 

CD 

P 

•rl 

3 

a; 

E 

0 

e 

(3 

CD 

e 

CD 

a 

B 

0 

%-» 

IH 

to 

UH 

.» 

CJ 

UH 

* 

to 

UH 

a 

03 

UH 

rH 

0) 

CD 

CD 

CD 

CD 

T3 

T3 

T3 

HD 

T3 

148  THE  TREE  EXAMPLE  Chapter  7 


to  -h  g» 


4-) 

,_» 

•H 

0 

*-» 

X! 

to 

tj 

s 

o 

&> 

3 

id 

•H 

13 

•H 

•rl 

^-^ 

rl 

rl 

•H 

CD 

TJ 

o 

o 

1 

£ 

(0 
iH 

•rl 

rH 
«J 

* 

^ 

(V 

P 

>>^- 

c 

X 

>1 

O 

P 

1     '-» 

•rl 

P 

^ 

P  — » 

rH 

i 

rH 
Id 

a 

to 

rl 

« 

CJ> 

•rl 

u 

X  — 

CD    >, 

C     1 

£ 

^» 

o 

0 

<^ 

p 

O 

to 

•H 

•rl 

CO 

+ 

X    X 

■a 

s 

P 

rl 

n 

El 

«-* 

I     CD 

C 

•H 

a 

CD 

P 

■H 

>    C 

•H 

TJ 

o 

«H 

C   TJ 

c 

CU 

> 

A3 

uS 

•rl 

CD 

e 

T3 

CD 

C    X 

1 

TJ 

>■, 

0) 

p 

>  J 

c 

>, 

to 

iH 

X 

0    CD 

a> 

x 

P 

H 

« 

TJ    C 

rH     CO 

I 

13 

3 

B 

«"^ 

c 

d)   ^ 

^ 

» 

CD 

cr 

CN 

•H    fc 

A 

0 

E 

CD 

CM 

>    . 

id   \ 

tj 

CD 

iH 

f-i 

rS 

rH   \ 

to 

13 

rl 

1 

* 

to 

id 

£      ^ 

0 

•rl 

•H 

CD 

P 

P 

—    CD    X 

&> 

•rl 

> 

3 

U 

c 

0 

CN      rl 

C    >i 

tj 

cr 

id 

* 

CD 

P 

TJ    CO 

•rl 

It) 

<D 

ft  en 

E 

1 

^H    S 

iH       1 

H 

rl 

to 

c 

CD 

CO 

P    -H    -rl 

>^ 

P    — ' 

a 

1 

i 

■H 

iH 

iH 

.C    43    TJ 

(0 

X 

CD 

rH 

•p 

O 

■H 

O 

&>  t>  a) 

M3 

rl 

It) 

CD 

03 

d 

•H 

•H      1      U 

TJ     CO 

1 

tj 

n 

& 

a 

•— 

cr 

rl 

U    TJ 

O  TJ 

(D    0 

rH 

TJ 

to 

u 

CD 

CD 

(3    S 

rl  -H 

•rl 

««» 

•H 

1 

C 

iH 

>H 

cr  p  (d  o 

TJ    <d 

CD   TJ 

M4 

,13 

>( 

> 

4H 

H 

•H 

c 

0) 

4H      1     T3 

c    P. 

P    id 

rH 

O 

•rl 

rH 

it) 

1 

rH 

■rl 

in 

CD    HH     (3 

■rl 

(3    in 

ai 

X 

■0 

CD 

o 

>, 

id 

rH    rH    -rl 

i  * 

0 

to  to 

■0 

c 

CO 

•H 

g 

N> 

-p 

CD     » 

O    X 

d) 

c 

S 

•H 

-P 

>> 

TJ 

\ 

4H 

+     CO 

*"   X 

1 

rH     0) 

It) 

0 

TJ 

iH 

c 

■H 

CD 

^^     1      CO 

>>  + 

•O   TJ 

1 

T) 

rH 

a 

CD 

+ 

cu 

> 

r-\ 

S    CD 

<w    0) 

id  ~ 

(3     0 

<M 

c 

■rl 

CD 

> 

~-^ 

iH 

■rt 

X 

\  id  TJ 

iH    rH 

rH 

<D    C 

H 

•H 

c 

CO 

* 

TJ 

TJ 

•H 

+ 

\    U    0 

CD    U 

ft~ 

r3      •• 

CD 

* 

— 

II 

rH 

c 

•H     1 

-^ 

—  TJ    C 

V)    U 

to  to 

CO 

+ 

■rl 

■H 

>o  ~^ 

•  •     1 

1     -H 

•H     3 

4H    a 

IH 

TJ 

-^ 

^43 

id 

II 

II           P 

S    u 

TJ   -H 

•H    0) 

* 

H 

C 

I 

CJ 

C 

U     II 

o  o 

id   i 

..  <o 

1     -P 

(0 

CD 

•H 

V 

■P 

■H 

■P 

X           CD 

TJ    id 

(d 

Tj   -H 

rl 

CO 

A 

a 

X 

fi 

C  P 

A 

i  tj  a 

£      iH 

S3     I 

•0 

1 

•H 

CD 

■H 

cr 

•H   IW 

&>  ? 

••    M 

O 

d)    <D 

St 

&> 

1 

C 

CD 

CD 

•H 

CD    CD    O 

TJ 

TJ    X 

10    > 

A3 

c 

>> 

0 

iH 

H   rH 

rl 

C   to   O 

0)    •• 

a 

••   -rl 

CD 

rl 

(3    -rl 

A 

TJ 

■H     1 

P 

tj  TJ 

CD     U 

4H 

V 

M 

iH 

rl     U 

rl 

rl 

O    > 

>  — ' 

S    -H 

0 

U    S 

CD 

•H 

0 

0 

0    0 

0 

0  o 

(3    0 

0   E 

fi 

•o  p 

N 

» 

4H 

4H 

•4H   MH 

MH 

>*H  TJ 

■Z  t3 

rH   TJ 

TJ  -H 

UH 

rH     O 

•H 

c 

CD     Pi 

fl  n 

rH 

•H     0 

0 

ft 

TJ   -rl 

A     CD 

•rl    ft 

tj 

CD    A     U 

e 

8 

0    > 

a]   to 

*    •• 

0 

CO 

O    P 

CD 

^ 

rH   ^ 

.£3 

CO 

e 

H 

P  TJ 

tj 

p 

T3 

c  .2 

^ 

^^ 

CD    (3  TJ 

a 

(V 

a 

CD   TJ 

e  a) 

C 

01 

E 

CD 

■S  w 

uh  to 

ItJ 

to 

MH 

CO 

S 

Section  7.4  The  Program  149 


•• 

P 

o 

X 

■d  * 

S 

G  cr. 

0>    G 

i) 

X 

<»^> 

0)   -H 

u 

03 

(N 

~    O 

a 

10 

e 

(0           '-- 
0          <N 
ft          CO 

CO 

to 

>,          0 

'0    rH 

rH 

g 

X) 
03 

C           ^ 

10     <d 

03 

o 

P 

CO 

P    4-> 

P 

O           (N 

ft       to 

1      (3 

0 

XS 

rH 

X  o 

P 

03 

03 

03 

-^ 

X        o 

(0     N 

rl 

P 

p 

ft 

-~~ 

e  -h 

0 

1 

0 

O 

--^ 

<N           X 

H 

CO 

1    u 

p 

X 

P 

P 

4H 

u 

■H 

G 

4-1    O 

G 

03 

r-t 

(N 

a 

X3 

G  .G 

■H     * 

„ 

•H 

e 

03 

to 

0) 
CO 

t-         u 
to            — 

03 

CO 

0 

a 

cu 

ft       to  ~ 

n 

P 

•  g 

G 

tn 

p 

u 

*-» 

--» 

X3 

-p 

0 

•H 

to 

G 

c 

rH 

>^          O  (N 

g 

rH 

rH    A 

X> 

cr 

•H 

•H 

* 

to 

T3 

»-» 

CO 

•H 

ft   >, 

0 

■H 

•rl    P 

03 

CD 

X> 

to 

p 

p 

rH 

c 

p 

X 

«-           >^ 

£ 

G 

A 

P 

P 

X) 

xs 

X) 

to 

C 

•P 

<D 

c 

U 

CO   -»          (N 

0) 

O 

03 

03 

03 

■H 

T3 

<D 

X! 

P 

01 

0   <N   r-     X 

P 

^-* 

rH 

rH 

0 

a 

rl 

P 

rH 

rH 

e 

O  "O 

s 

01 

ft  ^  to 

■H 

•H 

G 

•rl     II 

u 

-p 

■H 

D 

rH 

0) 

> 

X<2&^ 

3 

en 

G 

0) 

G 

c 

p 

0 

X 

^ 

P 

•H 

p 

0 

cr 

G 

P 

&>T3 

•H 

o 

p 

03 

G 

O 

•H 

A 

•H 

e 

»-  X  X 

<u 

co 

•H 

rH 

X) 

rH     G 

g 

.G 

c 

e 

P 

■-* 

4H 

3 

-o 

O 

-~~ 

3 

CD 

p         «- 

p 

+J 

XS 

■H 

rH 

■H   -H 

CD 

0) 

■H 

i 

G 

rH 

cr 

<H 

r-{ 

cr 

rH 

P 

-<-    r-     X 

i 

G 

03 

G 

■H 

G  -0 

co 

o 

<v 

4H 

P 

^-. 

0) 

0) 

•H 

-o 

•H 

CD 

•H 

S    >.  P 

<u 

<D 

P 

^ 

XI 

— ^ 

flj 

o 

>d 

c 

CD 

T3 

to 

p 

x: 

rH 

C 

P 

C 

O                  0) 

u 

e 

CD 

U 

0)    0) 

ft   01 

« 

•P 

P 

rH 

i 

U 

•H 

P 

x>  ^-   to   G 

03 

0) 

03 

^ 

U 

O    ft 

II 

CO 

a 

P 

■H 

P 

cu 

i 

X\ 

P 

(1) 

— 

c 

G    X    CD  -H 

a 

p 

c 

03 

g 

(0     1 

CO 

(1) 

.£ 

C 

o 

0) 

u 

G 

0 

CU 

CD 

•rl   «^  X>   rH 

co 

•H 

CD 

a 

•H 

ft  u 

X? 

p 

P 

N 

r^ 

<J 

0) 

03 

> 

aj 

03 

p 

P 

S            0      1 

1 

G 

~^- 

P 

CO 

to  o 

03 

o 

+ 

u 

■rH 

rH 

1 

c 

p 

a 

0 

cr 

p 

a 

<D 

03 

—  XJ    G    * 

p 

cr 

X) 

| 

O 

~  ,C 

P 

0) 

._ • 

cu 

e 

T-i 

T3 

0) 

03 

to 

e 

rH 

03 

CO 

rH 

a 

G     1      03 

0) 

0) 

0) 

rH 

g 

rH 

rH 

•H 

id 

13 

P 

a 

1 

0) 

ID 

a 

CU 

CO   -H    4H     P 

Cn 

P 

o 

■H 

P 

u  u 

P 

rH 

I 

rH 

X 

c 

03 

T3 

i 

XI 

p 

T3 

i 

-d 

T) 

T3 

CD    A    0   TJ 

(0 

-G 

0 

0 

0    0 

0 

0 

0 

It) 

•H 

rH 

p 

CO 

^-^ 

p 

CO 

c 

■d     1      1     •• 

0) 

a 

O 

'tH 

4H    4H 

4H 

O 

to 

O 

e 

4H 

■H 

0) 

3 

0) 

rJ 

CD 

0    CD    10 

CD 

u 

CO 

* 

0) 

^1 

to 

rH 

<D 

C 

CO 

rH 

0) 

CO 

G    G    <D    > 

T3 

03 

r-( 

4-> 

a 

13 

O 

4H 

n 

0) 

4H 

T3 

«-» 

1     rH    tn   O 

0 

a 

g 

rH 

CO 

0 

0 

0 

P 

O 

V    (0  X)  XJ 

G 

V) 

3 

•H 

0 

C 

T3 

T3 

G 

•o  -o 

C 

P 

O    >    CD    G 

0 

c 

rH 

rH 

rH 

rH 

4h 

rH 

<-{ 

4H 

G 

CD     1       1     -rl 

4H 

■H 

•H 

r-{ 

•H 

•H 

r-i 

'V 

G    CD  x)    S 

X) 

(1) 

_ 

•o  .c 

^1 

1' 

n 

X!    X\ 

0) 

T3 

P 

G    rH     G 

0 

N 

4-4 

0 

U 

O 

W 

0 

O 

o 

CO 

O 

03 

0     ft -H    X) 

.G 

■H 

p 

•H 

J3 

-C 

£1 

a 

O    -H    4H     G 

P 

0 

0) 

p 

^1 

-o  -o 

p 

cr -o 

T3 

P 

4J  *--    CD 

a; 

B 

rH 

OJ 

CO 

c 

c 

0) 

4J 

C 

c 

0) 

T3 

G    rH            10 

g 

CD 

e 

3 

0) 

CD 

e 

CD 

d) 

0) 

e 

G 

G    G        — 

4H 

e 

4H 

a 

CO 

CO 

4H 

to 

CO 

CO 

4H 

■d 

4H     6 

0) 

D 

0) 

0) 

<D   ~ 

X) 

T3 

T3 

X) 

X) 

150 


THE  TREE  EXAMPLE 


Chapter  7 


0 

^-» 

ft 

»-» 

X 

CM 

^                        — 

u 

■CJ                      — 

CO 

TJ  XI  £i  .G  .G 

a 

+J    4->    4-»    -P 

*    tx>  cj>  &1  &> 

>, 

~  G    G   G   G 

a>  cu  cu  cu 

^  rH   iH   iH   rH 

CO 

0 

^ 

ft 

t-    t-   CN   <N 

X 

X    >H    u    u    u 

,_ 

H  ~ 

*■"•   *  fl  "O  t)  "o 

T— 

T~                   *        *        #        * 

0)     (0 

(Q       +     «_-    ^    ^    — 

OJ    0 
•O    ft 

ft"    S     \     N     N 

O    X 

>>P     \     \     \     \ 

g 

i  cn 

cm  tr 

>4-l     0) 

0)     01   r-   r-   (N   CN 

0    0 

O   -H     (0     (0     10     0) 

1  ft 

ft—   0    0    0    0 

>,      ft  ft  ft  ft 

CO    X 

V 

X!    X    >.  X    * 

0>    I 

1  +J 

X)  ~ 

w-      (J*     +       +         1           1 

CU 

T>  TJ 

•O    rH     tO 

G  — 

w  ^    0) 

•rl  — 

n 

M-t 

iH 

to 

G  P 

> 

0     CU 

« — 

4-1    rH 

0)    ~ 

TJ 

id 
u 
p 

(0 

a 
o 
o 

v  u 

%% 
u  u 

UH     O 

I  £1 

<y  .. 

cp  > 

H  -P 

4J  ^ 

M 

O 

> 


c 

M  cu 
to  > 
i«   <v 


G  ft 
G   co 


rH  rH     CU     G     G 

I  o    m    H    H 

g  O     U    X\    £ 

d)  ••  V   P   P 

p  «-».... 

■H  —    G 

..  —  -H     G 

a>  is  -h 

a>  G  6  * 

G  «J  —  e 

*  ft   -' 

ft  i  +» 

i  u   G  co 

G  cu  o  cu 

c  c  >^  n 

cu  cu  to  -h 

g  +J    rH     CO 

I  «»•••• 

_  T3  .H   —  ~ 

CD     G  rH 

G    «  I     g 

•0     g  ft-H 

ft    g  CO     IT) 

ft     I      O  -rl     g 

10     CD     O  rH   ~ 

•H     0)     ••  ••   — 

rH     H     >  >  «• 

»       +J    +J  .p 

CO 

a>   a;   0  ft  c 

C    <d    G  co    o 

HJ     H     0)  -H   -H 

ft+J     g  rH    P 

4j   i  — -  —  - —  m 

in  tj  —  y 

■HO)'  G 

rH    P  &> 

ft    O     CO  -H 

i    at   a>  uh 

P   rH     G  G 

■H     0)     Ifl  O 

G    co   ft  O 


M    -H 

C 

•H     &» 

A    C 

P   -H 

•o 

S   -H 

0  n 

c  u 

0) 

^  > 

CU    0 

M 

(0 

P   n 

O    ITJ 

a) 

rH     CU 

CU    ? 

(0 

■o 

CU    0 

A  A 

V   V  ~ 

a)    • 

CU     g    UH 

CO           rH 

0     CU     tt> 

n)  X!   to  ~ 

O    En    P  — 

CU  >—  -H 

„ 

J3              ~ 

0) 

CU    CO 

iH 

*_ 

-  •  a  » 

0 

*-* 

J    CU    i0    0 

& 

u 

I    g  n  -o 

+J   id  w  C 

•H 

<D 

O    U     1    -H 

n 

UH 

11    IH      ID     J 

*J 

CU 

4H 

rH      1      0)      1 

tO 

4-1 

s 

CU    CU    fc   T3 

CU 

IH 

£1 

CO    CU    P    CU 

M 

3 

H         -P 

cS 

X) 

0 
■H 

10   P    CU    o 

•h      x;  <i> 

0 

>     10    P   rH 

•H 

V 

P 

1 

(V 

cu  UH    c    to 

•H 

4-> 

0) 

rH     0     U      1 

C 

<l) 

M 

XJ            3     »H 

•H 

V) 

-P 

•H   T)    P     0 

(0     10     0)   UH 
CO    CU    M     1 

iH 

2 

CU 

CU    P           CO 

CU 

a 

C 

O    01   T3    10 

JJ 

CU 

* 

O     d    rH    -rl 

4H 

e 

ft 

fl-ri     3H 

It) 

T3 

0    i0 
CU    H    >    •• 

CU 

C 

S    <"  _ 

a> 

c 

CU 

.0  c  -o  5> 

g 

(0 

to 

u  a)  c  e 

3 

ft 

UH    P     10     10 

iH 

i 

CO            VH 

<4H 

X) 

UH 

H   -rl     CU    UH 

0) 

1 

c 

rH 

3   rH     g      1 

G 

CU 

CU 

V 

O     1      10    CU 

<0 

CU 

CO 

to 

ft  n  cu 

a 

u 

CO    CO    UH    u 

i 

V 

T3 

CU   -H      1     -P 

T) 

<+H 

c 

>!H     li- 

CU 

iH 

CU 

lt           -H 

P 

? 

<U 

to 

to 

g    i0    to  T3 
iO    0 

O 

(1) 

fl 

co   co  A  ^ 

rH 

+J 

TJ 

•H  *              -P 

CU 

<u 

C 

Xi  P    C   cu 

to 

g 

CU 

e-i  -H  o  e 

HH 

CO 

UH 

> 

a> 

...    ...    .►    CU 

P 

■d 

T) 

Section  7.4  The  Program  151 


I 


ft 

B 

n 

p  <«  a»  a>  i 

(0  o  -p   >  0 

to  c 

cd  p  -h  *o  —       a» 

a  w  in  o  BE 

(0  -H          ,C  0) 

ftrH     CD    P  P            AJ 

CO)  -H            CO 

a  a)  i«  a  i        rtt 

to  43  o.  to      e 

■h  +j      a>  a       i 

^       ft  ,g  c 

V    (0  Eh  CO 

V  M  •<*  -*  OP 

45     (0    rH  -HP 

p    g  p  ~   3 

CD    <U   ,C   P  M   <w 

CD   ,*    P   -rl  ~                                                                                                                                                            d)H     B 

CO  -H  —                                                                                                                                                            ft    CD    CD 

t— I    <U    CO  O    to  P 

>,       >  a>  a)                                                                                                               -h  ~ 

cucoroxc  a»  — ~   i  — » 

«t?^'H  *                                                          ~-                                                                                             PftC  — 

G          <W  ft                                                           C                                                                                              3   -H    CD  — 

P-HT3  I                                                                 O                                                                                                     OrHCO   — 

O   43   rH     10  Tj                                                               -rl*                                                                                              llfl     0« 

cd  P    3  -h  cd                                                 V  U                                                                         X         ,C    ft 

rH            O   .C  P                                                                OCO                                                                                              CU-dO-H 

CD     tO     >    E-l  O                                                                C-H                                                                                               I      M           rH 

coat  a)                                       0i-i                                                         +j-hi3X3 

O    P  rH                                                               «H     «                                                                                              9    A     G 

a)  t3  h    •  at                                        ii                                                          OPcu'd 

4*                 ~  CO                 ~                                     rH    CD                                                                                       CD   —    g    G 

p  43       cd  ••           ~                        cd  ft                                                      p,       ••  o 

cu-h0(Opo  cd  p                ^                                      p  ft       cd 

>!    43     £3     M  -                 Tj                                        rHI                            CD                                                                ••   -H     CO     0) 

<d     U     CD    »4H  fi                                           I      g                           U                                                               ^rH-H-^ 

ggl^.H  ft   CD          ~           O                                                                  XI 

g           CD  £3                  £                                       O    P          ~           £3                                                            CO           D    CD 

OCDgCD  O                   I                                       P  -rl          ~           CJl                                                          -H   TJ    £3    P 

p    p    CD    M  ~  -H                  CD                                        II            -H-H                 ~                                             £3    CD    3 

CO    P    P  —   P                  CD                                       £    CD          <N                                3                                       COOgO 

•OJ^tO  O                  U                                       OCD^-P                  O                                       gOCD 

•H    10    >,  CD  ~  ~    CD                P                                    T>    M          rH           CO                TJ                                     CD    CD  TJ    X 

fl        m^  •  »h                                 co        fi  p        43        cd             C                           -PcofiCD 

>          P  >    >    CD                 a                        g          -H    *           ••           M                -H                                    -H  —    flj    •• 

POCDOOCQ  H                         CD           S                  CO          «4                  2                                                     g 

CO   TJ   43    M  T3   Tl     I                    X                         P            IP           -P          ~                 —                 rH   ~           0)   rH  *      ~ 

2CP0GCH  -H                          -H            CD     10            (3                                                       -H-HgrHOft 

•n  -H           IH  -H   -H     O                    g                            I              41   'H   H     O           -                   C                    G     >>                  (tf           -H 

£    *W  3     3    <+H                      I                               CD             M    rH    -H    u-t            p                     O                            P             gOgrH 

CD           OCDIII  P                         >           P    rf    (3   ~          -rl                 -H                 —     I             O    fi    Ofl 

>     CD           O  rH    CD    CD                  O                        -H^l^              £3                 p                  ft   J*,          M     3    M 

43    £3    £3  flJ   rH     g                  CD                        P          »       CD    ft                -rl                  O                  O    (3          <4H   <4H   4H   43 

&>  p  o  o  -h  43  m          in              -h           ftio.-           c           o  m-      -      +j 

fi-rlplflC  CD                           CO            0)     >,   M     «                                  3                  H    ••    P,   IH            (Oh 

•H    <+-l    P    t!  C    P     ••                  CO                         £           (OPCDg           M                 4-1                   I           -H     ft   CD    ft   3 

A     O    A    C  0)     O                            I                            CD            CD      I     >«      I             CD                     I                     ClHrH-HP-HO 

P           O    <0  CO    CD     CD                  CD                  CM           OgCP           P   --          rH                 ^H   H  XI  H    3  H   IH 


P  COrHfl  03  -HI  OCD-rlfi  <4-l   ~  CD--  (fltt)  A    U   X) 

1*   M    P    *4H    CD    CD     ffl  3  X    CD  M    P   rH     O  K)   U  >   "«  glOP  CD 

M     <fi     O    r-t  tOft  O  —  -H     01  a-H    X)    <M  "rH  CDft  ••  10   <«     X    <«   Tj 


flJ    ft   CD    CD    £3    ••     I                    g  ~    g    3           CD  HO  TJHOCDOG 

D          H    ffl    O          T)          ~     I  10  >C0  IO>C-H            I             CD 

GCDCDP           CDCD          —    O  >    CO    g  —  P  O  ft»H           OCDMhPPPW 

co  jC   to  -h    co    g  p              C  o   oi    i    M  TJ*  Oi         t)   m  ^  fl   S   fl)  - 

P              -HiDO         CDI  THI   O    O  'H  C»  PC         G~         gog 

CD           CDM           MCD           CCD  CO-HTSrH  -HO  l-H          -H           0*hCD^d 

^   to^    O   t7><nH         (OC  -HOtofift  U-O  ><0         SllPOftOC 

E-«CDP<WCICD           ftfl  >    h    <tJ  -H     I                                  IC  Og  I             0<4-l>,>4-ICD 

0)                 -HCDtO            Ift  I      ft  XJ     S    P  CD    -H  T3     ••           CDftCD           P           g 

0    fc     CD   TJ    CD    ••           CD    ••           CD H  CD    >  C                  CD   -H  t-l    •-    ••    •-   •• 

•CWOO-HH>           CD>  CD>>>C  Ml  -H>           HHO"--- 

M    C    <W    C    M    P    P           MP  hppp-H  PCD  SO          P-Qtfl 

010           OM-^                p_p^  I  ^CD  I    t)         -         - 

rCOlO—    CD-O  P                                  MCDC  U 

*>,OCM  M                     iH  T3PCD-HTJOO 

PfHOCDOOCD          O  O                      0  O    *  M£          Oiw-O 

^CDt3O^03>  >                         (0  X3  P                 43 

C>C-HCDP^(0  (0                     iw  PO*  -OPft 

OCD-H?MCD-rH  rH                         CD  CDPfiGCDO 

QrH>p(0g^4-l  »w                        -O  gCD  0CD           gO 

IH^-CH  <4H                           ••  H    01  IH    01           UH 

..*    .,...,..    d)    ,              qj  q)                        >_,  ci)    •— '           CD    — ^           CD   • 

•  «    aw    ■»    ••    ■«  rQ                     ir^  frj  rr^  »Q                     frj 


152  THE  TREE  EXAMPLE  Chapter  7 


<rt          ~                       —           fi  ft  10           0  -H 

v      ~               *      o  i  **  « 

4J          -                        C          -H  2  S          -H  O 

m       (o               *      -p  fi  ,         i  ft 

03                      -H  2*2 

p,     -h             «h      a  g  0       c  p 

£       5              ~      ft  -cog  o 

P  G  h 

jj         ..                   o        jj  nJ  fi        "O  = 

o                     00-  i  2      S  £5 

+J        O                                 0  o  |  «        -P 

•H         P                   P         O    g  0>  O  C 

C+j  0)  G         O  +J<1) 

r<           fl  C     U            C     fl  -C           -HI  G            P 

+5       C  o  p       -h  o  p       .c       0  ?>       S 

0  w  p  3       0  *o  »w       o       p  <o 

>       J  «j  o       0  0  —  os-P  a       co 

1  ^~.  CCUPO^»'-~  >iO  did) 

U  g  p        to  t-t    •  ~                              -h                 to  .22 

3—  3-HOO)  0)                                                H            •»          O  EG 

+J        G  O   »>       .C         ft  *d                                  2                   o  sm 

-w+J  o  «      p  >>  >,  o                            a               f  „,       2 

o          *              moag  p  2  o 


& 


0)0  0)0)  0)  o  —  —  C  C  d    _ 

cu  in      p  g  p  o  c  >^r-      0  ••  c  ^ 


•H«J13              P  <«         0    O  -n  C  ^    ^  *         S  *    , ,  *J 

C  -H                 P                  O   tO  «TJ  <W    X    _  *    -P  -H 

P    tO    0    10                  I       -          P  B     =  p  .*           fc  £    S    ? 

0)     (fl   -3   -rl                   (O-drHrHrH  Pi  "fl     S    E           1  ^     V     m 

<3o-HP                    |CpCfl>                     I  PEh  HJ    P     P 

ocu           p  0  o  tn  >>  =  m  r4  a   \        a  00 

~    .-   7   .C                 3  rH    P  -H   <2  \  +JJQWC  ftv;    « 

me-          toc+jop<w  —  johs  ■Vft-P 

O)5>*-H0OP  X   ~  t*          =  II 

ni+3pMtotoaje!<o  *  "  -K  tt       -  §  8  £ 

lH4-l~COiH0,l3"P  P  OWC  —           (UXflJ 

p            0   \           r-l     O                          PtO  O  CrHPq-H  -H           -H     g     ft 

W\             I      fi^H    (J>-    C  P   -»  ^          •HOW           P  C             lltQ 

I     w            gSPrHC            O  *    ~                  —  ^           Pll  O  «     «   -d 

to       Siw      p-sopifltu  crto           pto  ototo^-3  p       n^5 

P  HH 

14_|  t)     V 

(0  ••    tO  3     CU     CD    M-l 


'U         U*  ^J         Wi  -f         Wl  W         W<       V<  ^-  -»—  f-l         ^-         w 

H  Cffl>Q  PQJ  O0>        -H3!Dl<w  to         POPS 

1=0)3=0)=  (OP  OP  rHOOPI  -H  *g   = 


CQ)P"C  C  —   a)  10)          3    ••    ••    0>    3  «3          0) 

P  0)PP         0=0  —         P  rjP        '°^^2V  «,         a 

S  O  ge<=     -HO)  •H-'*"  <0--  ^  31  4)  >% 

O—O  I  >pprHP  P  0)  '    O    &,     O    10  P'*' 

TJ—P  TjaOIOlUPtJ  0    0*  P*  PTJJgtO  >i  I 

a  *  cScoppp  a>o?      —is       ccw/o)  p       g 

•HPTJ  JoZtfC-HC  PPO         -0)0  rO-HtO^O  I  « 

SOC  g        nJ        0)J0)  -P    i   "O  fi  "O       'd   ?  o—  g        P 

100  gPPg  g  IrHC  PPC  CI-OCOP—  0)  -H 

0PIO  OP0>0)3l03  Z     <H   -ri  0*-H  S0CCft—  P  I 

«*«-'  u  m>j  n  u  v  u  00>       o       >      t)  «  «  o^+j  -h      p 

n  i-P(do>ooo  CPi         p*i         0ptop  i         g 

JJ4J4J  0)  1)1  S  d!  fl  Q  1)  110  I+J0         MP  —  PC  0          O 

i   O    O  0  =     =     =••= :      •  •  P    0    0         P    O    0  —         3&i  0          0) 

00  p  —     —     —  p.cp      0OP      M_t!-flP  fl      81 

■a^fc  +j>—  flpptopp-H-dOP  p>» 

o—  *»  +)**o>**  ociia  *p 

45  —  t3  co  p  (o^i^^^-  1 

±i         a  u  W  0"0        -r\  ±)  Pt3 

0)P(0  <<J  C+JCCPC430-O  5*2 

gO)---  >  S00300PgC  ><0 

IUH  4-1  M-ICOlOd-ltOtO  <H<fl  VW" 

4)^,  0)  O)^^^^0^^^',*0^-'  0> 

<0  tj  '0'0«-,0  «o        +j 


The  Program  153 


0 
0 

rH 

rH 

,_^ 

u 
1 

•rl 

•H 

P 

rH 

9) 

TJ 

H 

-d 

a) 

CO 

rH 

c 

i 

Pi 

•rl 
X! 

o 

0) 

1 

0 

co  c 

1 

1 

T3 

M    0 

ai 

01 

» 

0 

0) 

(0   -H 

p 

s 

CO 

C 

Pi 

e  p 

(V 

id 

Pi 

■H 

1     -rl 

i-t 

c 

01 

rH 

0)     CO 

01 

Of 

CO 

£ 

T5 

W     0 

TJ 

M 

CO 

P 

(0 

3     ft 

1 

d 

0) 

0 

ai 

cy 

0 

>H 

rl 

e  p 

(0 

CO 

s 

0 

0 

S 

3 

4-1 

=*t 

=      0 

0 

0 

E 

p  p 

e 

e 

TJ 

rH 

P 

0 

rH 

01 

0) 

0  c 

■H 

£) 

0) 

OS  -H 

01  ~ 

■p  = 

01 

e 

= 

rH 

43 

CO 

a)  a> 

01      • 

« 

0) 

1 

M  <d 

rH     0) 

c 

TJ 

5 

tj 

0) 

(0    0 

01     0> 

0) 

0 

CO 

CO 

s  c 

Q    U 

a 

a 

55 

rl 

3 

E 

E    p 

B 

0) 

0 

(0 

CO 

p 

e 

Q)   -H 

a)  a> 

0) 

•H 

CO 

c 

-O  X! 

n  a 

TJ 

.C 

T3 

E 

w 

> 

0  P 

0  P 

0 

P 

0 

: 

p 

a 

a 

a 

Pi 

CO 

••  ^3 

..    m 

rl 

TJ 

T3 

P 

0 

0 

0 

rH 

*    tH 

* 

UH 

c 

« 

P     ? 

■P  P 

p 

P 

o 

CO 

co    3 

CO 

rH 

to 

CO 

— - 

£i 

•H    0> 

•H     0 

■H 

0) 

■H 

•H 

!>, 

rH     Q) 

rH 

rH 

A 

rH 

£ 

0) 

0) 

iC    H 

IT]     (1) 

« 

tT5 

IT] 

P 

■d 

* 

--» 

1    P 

1   -o 

rH 

1 

0 

> 

(9 

CO    0 

CO 

CO 

0 

c 

B 

■—• 

0 

ft   (U 

ft  G 

ft    5 

ft  p 

0 

> 

•d 

J*.c 

K 

>» 

0) 

J* 

rl 

0 

c 

■p  -p 

P    CO 
1     -H 

P 
1 

Pi 

p 

1 

■d 

H 

0) 

u 

£ 

4H 

3 

•rH 

e  >. 

e  a 

e 

a] 

a 

■H 

*— . 

c 

0 

01 

0 

■H 

0)    IT] 

0)    4-> 

0) 

CO 

£ 

•t 

fC 

T3 

c 

"3 

s 

Oi  — 

P    rH 

p 

p 

0) 

p 

u 

0 

p 

C 

•H 

C 

-d  p 

•H     ft 

•H    CO 

•H 

«d 

•rl 

■d 

CO 

■H 

rH 

•H 

CO 

o  c          — 

1      CO 

1    o 

1 

■H 

1 

id 

c 

c 

S 

| 

2e 

■d 

c  o>          ^ 

<D   -H 

CO  -H 

0) 

> 

CO 

•H 

P 

0 

—    M               '- 

a>  tj 

CO   rH 

0) 

C 

CO   TJ 

s 

0) 

0) 

0) 

c 

10               ~> 

m   a' 

U     ft 

U 

u 

rl 

TJ 

O1 

■d 

5i 

T3 

P    ft             X! 

P  06 

P    W 

p 

a, 

P 

< 

0) 

M 

0 

0 

0   ••        ^co 

*  = 

*    = 

* 

c 

* 

TJ 
0 

e 

c 

> 

P 

PJ 

p 
o 

0          —  P     CO 

U     W     ft    pj     SH 

0 

CO 

0) 

CO 

C 

0 

1       TJ      11      CI     <rl 

ft 

ft 

ft 

ft 

*-. 

0> 

^-~ 

0) 

*-* 

u 

-^ 

p  o  v  u  a) 

>> 

£ 

K 

>* 

tj 

& 

■d 

rH 

A 

T3 

£ 

i 

* 

C       C     £1      10       rH 

P 

p 

p 

p 

TJ 

rH 

co 

0 

0) 

CO 

0 

00 

0) 

CO 

0)        ~   ft  .. 

1 

1 

rH 

■  H 

0) 

Pi 

-Q 

0) 

Pi 

-— 

cu 

-d 

Oi 

n  -d 

B 

e 

e 

e 

•H 

£ 

in 

id 

rl 

0) 

Sh 

o 

-~~ 

rl 

<d   C  —  *    S 

V 

co 

0) 

CO 

£ 

u 

4H 

0) 

rH 

UH 

Oi 

P 

UH 

Pi 

0) 

IH 

ft   4)   P   P    0 

p 

P 

p 

p 

0 

1 

0) 

e 

| 

01 

P 

Oi 

OJ 

T3 

0) 

i    to  c  o  *d 

•rl 

•rl 

•H 

■H 

TJ 

M 

(0 

P 

Sh 

01 

rH 

rl 

CO 

0 

Sh 

0)<-   01    O    C 

1 

| 

1 

1 

>   TJ 

c 

01 

rH 

CO 

X 

Pi 

>i          Sh    rH  -H 

P 

P 

P 

P 

CO 

(0 

0) 

CO 

Oi 

■d 

(0 

iO   P    10    *     > 

3 

3 

3 

3 

G 

» 

rl 

s 

TJ 

5 

a 

* 

S 

e  c  ft 

0 

0 

0 

0 

0 

0 

0 

i 

P 

0 

i    oi       cr  tj 

V 

CO 

0) 

CO 

0) 

0) 

XI 

0) 

0) 

T3 

0) 

0) 

TJ 

0) 

0 

TJ 

<u  u  p  p  c 

ft 

ft 

a 

ft 

CO 

■d 

Pi 

CO 

T3 

Pi 

CO 

TJ 

c 

CO 

0 

c 

M    10     0    CO    CO 

rs 

K 

K 

I* 

3 

0 

•H 

3 

0 

•H 

3 

0 

•H 

2 

r^ 

•H 

3    ft  C   co   co 

p 

1 

p 

p 

P 

i 

a 

s 

i 

Pi 

s 

0 
5 

C 

* 

0 

e 

* 

£ 

or 

-0 

■0 

■d 

■d 

TJ 

T3 

TJ 

TJ 

TJ 

T3 

D"d 

I4H 

-d 

TJ 

■d 

TJ 

PS 

G 

C 

c 

C 

Pi 

a 

C 

C 

c 

p 

Pi 

C    P   -H 

•0 

ITJ 

aj 

id 

3 

0) 

0) 

3 

0) 

0) 

2 

CO 

Oi 

rJ 

0) 

0) 

rJ  co  -- 

UH 

no 

CO 

4-< 

CO 

CO 

UH 

CO 

DO 

<4H 

CO 

DO 

<4H   r-i 

> 

> 

> 

> 

0) 

0) 

01 

CO 

CO    — 

p 

P 

p 

p 

TJ 

T3 

TJ 

■d 

TJ 

154  THE  TREE  EXAMPLE  Chapter  7 


o> 

9)    H  -  IW 

■d           0)  >,  >W 

rd        XI  -O   3 

O     •  O  -P 

h   Ji   O  XI   co 

•O  -P 

91    O  <U  TJ 

XI   O   <D  .3   c 

!-t  -P       10 

e   T3  -H 

CO    0)   <4-l  tT>   >^ 

5  rH  C   T3 

S  -H    P  -HO 

ft   <0  -P    XI 

P     B   3  3 

■H    O    -P  ft   0) 

o  6  3 

H  OP 

O  P   o  o 

U    U    4-1  (1) 

O     0)  i+j    4_) 

nj  fc  -d  os 

e  n  a)  ft 

o  en  v  g 

<o  o  c  ho 

i0  2    O 

CO    P    M  CO 

+J    0>  id      ■  M    0) 

•h              g  3  = 

0*0    0)  CO   +J      • 

<u  p  c  p  0      p 

O           rO    CO  O      •>  rH 

C  TJ          >>  'riH    3 

•H    tt)      -   CO  •    >   -H    CO 

wh  iii  >,  a»  n  v 

•H    rH   =  T>     H             H                    ~ 

ft  -H     (I)  O     ft   CO                         — 

•    6    <H    J)  XJ          -HO)                 — 

•won  a>      xi          >> 

0)O<UP  —  »W  3    O    4->                 TJ 

N         P  =  >*,  O  P    O                      O 

■H     CO    (0  <0                 H    fi                 X> 

O-H    H    J)  O-PCO           u 

g         <03  J3htJ  iw   D 

<1>     <1>     ft  -P  3   rH    H    -P 

Eh   ti  M»  O         a>              C  — • 

•HCOdJ  ■Od)X!         fc               Cna) 

«w  *w        >«  o    U           •                    OS 

O           Art  X)          PT3C                 fc  rH 

CO           g  cdttJ-HlOQ)—           ftlO 

g-HC  .C           0)3—          —    > 

0XS-H3  o+JC+Jp--- 

•h-p^o  o       a>  co       g       a> 

•H    4H    O  *-    N    P   -rH    G    CO          H    O^ 

CO-HC  -H                   (OC            «H-> 

•h      +>  a>  «h  o    « "O       a>       >    .  --» 

'mp-h.c  in  Eh  id  u  tr         «       a) 

OJCOCS  N     «   H     «1    O  -          ^IH     3 

X><l)-H  .HgC0rH                    ~+JrH 

n  uh  p  o        i            (u           ai  io 

a>        a;  co  goc<uc!SOPco> 

£  mi)  h  oipoxj-h  i-ioa)—    - 

■PXJ-H  g            C                   lUHH 

P     CO   «W  O            C    P     >       -  — 

CO           -H  O     O     CO     <0   rH   — 

•HW^Tl  HrH-HOS—H 

«    P     01  CJ                           CO            O 

a>o       T3  loaiopai-P  — 

Mfe-Ptf  g     CO     O   -H     fc     <D  ' 

ttJW^O  4H    D   rH                  rH 

K   CQ    ft  rH  a>  =           frjOi  — 

■O           4H     C    45 
—         H    (0   P 


Section  7.4  The  Program  155 


7.5  Problem  Set  #7 

Questions 

1.  Write  a  function  which  puts  up  a  menu  with  five  choices:  "Truth,"  "False- 
hood," "Confusion,"  "Panic,"  and  "Mega-panic!."  Clicking  on  "Truth" 
returns  the  string  "Truth;"  clicking  on  "Falsehood"  also  returns  the  string 
"Truth;"  clicking  on  "Confusion"  randomly  returns  one  of  the  strings 
"Truth"  or  "Falsehood;"  clicking  on  "Panic"  enters  the  Fep;  clicking  on 
"Mega-panic!"  enters  the  Fep  and  does  a  cold  boot. 

2.  Use  the  tree  code  to  display  flavor  component  trees.  Ignore  "included- 
flavors"  if  you  like. 

3.  You  may  have  noticed  that  in  the  editor  (and  in  some  other  contexts),  put- 
ting the  mouse  in  the  top-right  or  bottom-right  corners  causes  the  mouse 
blinker  to  change  to  a  squat  vertical  arrow,  and  bumping  it  against  the  top  or 
bottom  edge  of  the  window  causes  scrolling.  This  behavior  is  called  "flashy- 
scrolling,"  and  is  controlled  by  the  flavor  tv:flashy-scrolling-mixin.  Add  this 
mixin  to  the  tree  window  and  write  the  necessary  methods  so  that  bumping 
the  mouse  against  the  top-right  corner  will  "scroll,"  i.e.,  make  the  parent  of 
the  current  root  be  the  root. 

4.  There's  an  awful  lot  of  duplication  in  the  graph  and  tree  examples.  The  right 
thing  to  do  would  have  been  to  take  out  the  common  portions,  and  build 
graph  and  tree  on  top  of  them.  Re-implement  graph  and  tree  in  that  fashion. 
(It  sounds  like  a  lot  of  work,  but  I'll  bet  it  won't  take  more  than  an  hour.) 


156  THE  TREE  EXAMPLE  Chapter  7 


Hints 


Your  function  need  simply  call  tvrmenu-choose  with  an  argument  of  an 
appropriate  item  list.  See  section  14.3  of  volume  7  for  a  description  of  the 
possible  forms  for  menu  items.  The  last  three  menu  items  will  have  to  be  of 
the  "general  list"  form. 

Constructing  a  tree  which  corresponds  exactly  to  the  ordered  list  of  flavors 
used  for  building  combined  methods  is  tricky  because  of  "included-flavors." 
But  it's  not  hard  to  make  a  tree  showing  the  regular  components.  Given  a 
flavor's  name  in  the  form  of  a  symbol,  (  si  :  f  lavor-depends-on  (get 
flavor-name  'si: flavor))  returns  a  list  of  the  components.  Give  the 
node  corresponding  to  a  flavor  one  child  for  each  of  the  flavor's  components, 
and  recurse  on  them.  To  make  the  tree  fit  on  the  screen  you'll  probably  want 
to  switch  to  a  smaller  font,  and  decrease  the  values  of  *vertical-spacing*  and 
*  horizontal  -spacing* . 

The  best  way  to  find  out  about  tv:flashy-scrolling-mixin  is  to  read  the  source 
code.  There  isn't  very  much  of  it.  You'll  have  to  write  methods  to  handle 
the  messages  :  scroll-more-above  and  :  scroll-more-below  (which 
should  return  t  when  it  is  meaningful  to  scroll  in  the  given  direction  and 
nil  when  it  is  not),  the  message  :y-scroll-to,  which  should  do  the 
actual  scrolling,  the  message  :scroll-bar-p,  which  allows  or  inhibits 
scrolling,  and  the  message  : handle-mouse-scroll.  I  suggest  that 
:  scroll-more-above  return  nil  when  *root*  is  eq  to  *the-real-root*, 
and  t  otherwise;  that  :  scroll-more-below  always  return  nil;  that 
:y-scroll-to  call  the  function  mouse-make-parent-root  on  *root*  and 
self;  that  :scroll-bar-p  always  return  t;  and  that  :  handle -mouse - 
scroll  always  return  nil.  (The  : handle-mouse-scroll  method  isn't 
directly  related  to  flashy-scrolling,  but  because  our  :scroll-bar-p 
method  returns  t,  the  system  is  going  to  think  that  in  addition  to  flashy- 
scrolling,  we  have  a  standard  scroll  bar  in  the  left  margin.  So  every  time  the 
mouse  bumps  against  the  left  margin,  our  window  will  be  sent  that  message. 
The  method  needn't  do  anything,  but  it  had  better  be  defined  or  we'll  get  an 
error.  This  may  sound  like  a  modularity  problem,  and  in  fact  it  is.  It 
appears  that  someone  assumed  only  windows  with  scroll  bars  would  use  flashy 
scrolling.)  Don't  forget  to  make  another  tree-frame,  since  mixing  in 
tv:flashy-scrolling-mixin  will  be  an  incompatible  change  to  tree-window. 

The  basic  part  might  define  flavors  node,  node-window,  node-pane  and  node- 
frame,  and  methods  for  them.  Graph  would  then  build  graph-node  on  top  of 
node,  and  graph-pane  and  graph-frame  on  top  of  node-pane  and  node-frame. 
Tree  would  similarly  build  tree-node  on  top  of  node  and  tree-pane  and  tree- 


Section  7.5  Problem  Set  #7  157 


frame  on  top  of  node-pane  and  node-frame. 


158  THE  TREE  EXAMPLE  Chapter  7 


Solutions 

1.  (defun  silly-menu  ( ) 

( tv : menu-choose 
' ( "Truth" 

( " Fa 1 s  ehood "  " Truth " ) 
("Confusion"  :eval  (nth  (random  2) 

'("Falsehood"  "Truth"))) 
("Panic"  :funcall  sirhalt) 
( "Mega-panic  I "  :eval  (sirhalt  (format  nil  "b~%" ) ) ) ) ) ) 

2.  Here  is  a  crude  first  pass  at  making  flavor  component  trees.     It  ignores 
included  flavors  as  well  as  duplication  of  components. 

(setq   *vertical-spacing#    5) 
(setq   *horizontal-spacing*    10) 

(send   *tree-window*    : set-font-map    '( fonts : tiny ) ) 

(defun   show-flavor-tree    (flavor-name) 
( start-new-tree ) 
(send   *the-real-root*    : set-label 

(format  nil'  "~S"    flavor-name)) 
(show-flavor-subtree   flavor-name   *the-real-root* ) 
(send   *tree-window*    : refresh ) ) 

(defun   show-flavor-subtree    (flavor-name   parent) 
(loop   for   component- flavor 

in    (reverse    ( si : f lavor-depends-on 

(get   flavor-name    'si : flavor )) ) 
for  node   =    (make-instance    'node    : label 

(format  nil    "~S"    component-flavor)) 
do    (send  parent    :add-child  node) 

(show-flavor-subtree   component- flavor  node))) 

We  can  avoid  duplication  by  keeping  a  list  of  all  the  flavors  seen  so  far,  and 
using  a  new  flavor  only  if  it  isn't  already  on  the  list.  (Modifications  in  upper 
case.)  If  you  want  try  accounting  for  all  the  vagaries  of  "included-flavors," 
look  at  the  function  si:compose-flavor-inclusion 

(DEFVAR    *SEEN-LIST*) 


Section  7.5  Problem  Set  #7  159 


(defun  show-flavor-tree  (flavor-name) 
( start-new-tree ) 
(send  *the-real-root*  : set-label 

(format  nil  "-S"  flavor-name)) 
(LET  ( (*SEEN-LIST*  (LIST  FLAVOR-NAME))) 

(show-flavor-subtree  flavor-name  *the-real-root* ) ) 
(REVERSE-ALL-DESCENDANTS  *THE-REAL-ROOT* ) 
(send  *tree-window*  : refresh)) 

(defun  show-flavor-subtree  (flavor-name  parent) 
(loop  for  component-flavor 

in  ( si :f lavor-depends-on 

(get  flavor-name  'si: flavor)) 
UNLESS  (MEMQ  COMPONENT- FLAVOR  *SEEN-LIST*) 
DO  (LET  ((node  (make-instance  'node  rlabel 
(format  nil  "~S" 

component-flavor) ) ) ) 
(PUSH  COMPONENT- FLAVOR  *SEEN-LIST* ) 
(send  parent  :add-child  node) 
(show-flavor-subtree  component-flavor  node)))) 

This  function  will  make  nonsense  of  any  existing  space  requirement  info. 
Fortunately,  we  can  be  sure  there  won't  be  any,  since  these  nodes  were  just 
created  and  have  never  been  displayed.  (We  couldn't  just  reverse  the  chil- 
dren as  we  get  to  them  the  way  we  did  above  because  then  we'd  keep  the 
wrong  node  when  a  flavor  appears  more  than  once.) 

(DEFUN  REVERSE-ALL-DESCENDANTS  (NODE) 
(SEND  NODE  : EVAL-INSIDE-YOURSELF 

'(SETQ  CHILDREN  (NREVERSE  CHILDREN))) 
(LOOP  FOR  CHILD  IN  (SEND  NODE  : CHILDREN) 

DO  (REVERSE-ALL-DESCENDANTS  CHILD))) 

3.  (def flavor  tree-window  () 

( tv:f lashy-scrolling-mixin    ;  this  was  added 
tv : process-mixin 
tv: basic-mouse- sensitive-items 
tv: window) 
( :default-init-plist 

: process  ' (tree-window- top-level-function) 
: item-type-alist  *tree-item-type-alist* 
:blinker-p  nil 
: font-map  ' (fonts :hl12i )) ) 


160  THE  TREE  EXAMPLE  Chapter  7 


(def method  (tree-window  : scroll-more-above)  nil 
(neq  *root*  *the-real-root* ) ) 

(def method  (tree-window  : scroll-more-below)  nil 
nil) 

(def method  (tree-window  :y-scroll-to)  (ignore  ignore 
(mouse-make-parent-root  *root*  self)) 

(def method  (tree-window  : scroll-bar-p)  nil 
t) 

(def method  (tree-window  : handle-mouse-scroll )  nil 
nil) 


4.   See  the  file  "book:  tape;  graph &tree.lisp' 


Chapter  8 

RANDOM  USEFUL  TOPICS:  RESOURCES  &  SYSTEMS 


8.1  Resources 

The  documentation  on  resources  (chapter  1 8  of  volume  8)  is  not  bad.  What  follows 
is  primarily  a  condensation  of  it. 

In  cases  where  a  program  uses  and  then  discards  large  objects  at  a  high  rate,  it  can 
be  worthwhile  to  do  the  storage  management  manually,  rather  than  relying  on  the 
garbage  collector  to  eventually  clean  up.  The  resource  facility  provides  a  simple 
way  to  do  so,  and  is  widely  used  throughout  the  system  software.  The  Chaosnet 
code  allocates  and  frees  packets,  which  are  moderately  large,  at  a  very  high  rate. 
The  window  system  allocates  and  frees  certain  kinds  of  windows,  which  are  very 
large,  moderately  often.   Both  use  resources. 

For  each  resource  defined,  there  is  a  free  list  kept  of  suitable  objects.  Allocating  a 
resource  involves  checking  the  list  of  available  objects  and  returning  one  if  there  are 
any.  If  not,  a  new  one  is  created  and  returned.  Deallocating  a.  resource  involves 
returning  a  previously  allocated  object  to  the  free  list.  So  the  storage  space  occu- 
pied by  a  deallocated  object  is  not  really  freed  in  the  sense  that  the  garbage  collec- 
tor reclaims  free  space;  it  does  not  become  available  to  be  used  as  part  of  any 


162  RANDOM  USEFUL  TOPICS:  RESOURCES  &  SYSTEMS         Chapter  8 


newly  created  lisp  object.  The  original  object  continues  to  occupy  the  storage 
space,  but  may  itself  be  reused  through  being  allocated  again. 

The  four  functions  and  macros  which  together  compose  the  resource  facility  are 
defresource,  for  defining  a  new  resource,  allocate-resource,  for  allocating  an  object 
from  a  resource,  deallocate-resource,  for  freeing  an  allocated  object,  and  using- 
resource,  which  temporarily  allocates  an  object  and  then  deallocates  it. 

A  call  to  defresource  looks  like  this: 

(defresource  name  parameters 
keyword  value 
keyword  value 
...    ) 

name  should  be  a  symbol,  which  will  be  the  name  of  the  resource,  and  which  will 
get  a  defresource  property  of  the  data  object  representing  the  resource. 
parameters  is  a  (possibly  empty)  lambda-list  of  pseudo-arguments  which  will  re- 
strict the  objects  considered  suitable  to  some  subset  of  those  on  the  free  list.  For 
instance,  a  resource  of  2D  arrays  might  have  two  parameters,  the  number  of  rows 
and  the  number  of  columns.  When  allocating  an  object  from  this  resource,  you 
could  specify  how  many  rows  and  columns  it  should  have.  The  free  list  would  be 
filtered  for  arrays  with  the  requested  dimensions  —  if  all  the  arrays  on  the  free  list 
had  the  wrong  dimensions,  a  new  one  would  be  created. 

There  are  seven  possible  keyword  options.  Only  one  is  required,  the  constructor 
option. 

constructor 

The  value  is  either  a  form  or  the  name  of  a  function.  It  is  responsible  for 
making  an  object,  and  is  used  when  someone  tries  to  allocate  an  object  and 
there  are  no  suitable  free  ones.  If  value  is  a  function,  it  is  given  the  internal 
data  structure  for  the  resource  and  any  supplied  parameters  as  its  argu- 
ments.  If  it  is  a  form,  it  may  access  the  parameters  as  variables. 

initializer 

Value  is  again  either  a  form  or  the  name  of  a  function.  If  an  initializer  is 
provided,  it  will  be  called  on  each  object  as  it  is  about  to  be  allocated, 
whether  the  object  was  just  created  or  is  being  reused.  If  value  is  a  func- 
tion, its  arguments  will  be  the  resource  data  structure,  the  allocated  object, 
and  the  supplied  parameters.  If  value  is  a  form,  it  may  reference  the 
parameters  as  variables,  and  also  the  allocated  object,  via  the  variable 
object. 


Section  8.1  Resources  163 


rchecker 

A  form  or  the  name  of  a  function.  The  job  of  the  checker  is  to  determine 
whether  a  given  existing  object  is  safe  to  allocate.  If  no  checker  is  specified, 
the  default  action  is  to  consider  an  object  safe  if  it  is  not  currently  in  use 
(i.e.,  has  not  been  allocated  without  being  deallocated).  If  you  specify  a 
checker  it  will  be  used  instead.  A  function  here  will  be  passed  arguments  of 
the  resource  data  structure,  the  existing  object  being  considered  for  alloca- 
tion, the  value  of  in-use-p  for  that  object,  and  the  supplied  parameters.  A 
form  may  reference  the  parameters  as  variables;  the  object  under  considera- 
tion, as  object;  and  in-use-p.  As  you  can  see,  the  free  list  for  a  resource  is  a 
somewhat  hypothetical  object.  When  you  ask  to  allocate  an  object,  all  of 
the  existing  objects  are  initially  eligible.  The  default  checker  creates  the 
functional  equivalent  of  a  free  list  by  approving  only  those  objects  which  are 
in  fact  free,  but  you  needn't  have  this  behavior.  Supplying  your  own 
checker  will  change  it.  If,  for  instance,  your  checker  always  returned  t,  a 
given  object  could  be  simultaneously  in  use  in  any  number  of  places,  because 
it  would  always  be  considered  safe  for  allocation,  regardless  of  whether  the 
previous  allocater  had  deallocated  it.  And  if  your  checker  always  returned 
nil,  no  object  would  be  reused;  every  allocation  request  would  result  in  the 
construction  of  a  new  object. 

matcher 

A  form  or  the  name  of  a  function.  If  no  matcher  is  specified,  an  object  is 
considered  to  satisfy  the  supplied  parameters  if  they  are  equal  to  the  param- 
eters supplied  at  the  time  the  object  was  constructed.  If  you  specify  a 
matcher,  it  will  be  used  instead.  A  function  here  will  be  passed  arguments 
of  the  resource  data  structure,  the  existing  object  being  considered  for  allo- 
cation, and  the  supplied  parameters.  A  form  may  reference  the  parameters 
as  variables,  and  the  object  under  consideration,  as  object. 

rfinder 

A  form  or  the  name  of  a  function.  If  this  option  is  provided,  the  usual 
method  for  finding  an  object  to  allocate  will  not  be  used.  The  finder  will 
instead  be  expected  to  somehow  come  up  with  an  object.  The  checker, 
matcher,  and  constructor  will  not  be  called,  unless  the  finder  does  so  expli- 
citly. A  form  or  function  specified  here  will  see  the  same  arguments  as  the 
constructor  would. 

:initial-copies 

Value  is  a  number,  defaulting  to  0.  The  specified  number  of  objects  will  be 
constructed  when  the  defresource  is  evaluated,  thus  creating  an  initial  free 
pool  of  unallocated  objects.  If  a  resource  has  parameters  and  one  or  more 
initial  copies  are  specified,  the  parameters  must  all  be  optional;  the  initial 
copies  will  have  the  default  values  of  the  parameters. 


164  RANDOM  USEFUL  TOPICS:   RESOURCES  &  SYSTEMS  Chapter 


:free-list-size 

Value  is  a  number,  defaulting  to  20.  It  specifies  the  size  of  the  array  used 
to  contain  all  the  objects.  (If  the  number  of  objects  ever  exceeds  this  size, 
the  array  is  automatically  replaced  with  a  larger  one.)  :free-list-size  is  a 
misnomer,  since  the  array  contains  both  the  free  objects  and  the  ones  that 
are  in  use.  As  the  earlier  discussion  of  the  :  checker  option  pointed  out, 
there  isn't  really  any  free  list  at  all. 

For  all  of  the  options  which  accept  a  form  or  the  name  of  a  function,  if  a  form  is 
supplied  it  is  compiled  during  the  evaluation  of  defresource,  and  put  on  the  property 
list  of  the  name  of  the  resource. 

allocate-resource  resource -name  &rest  parameters 

An  object  is  allocated  from  the  specified  resource,  matching  the  given 
parameters.  The  exact  procedure  followed  depends  on  which  options  were 
supplied  to  defresource  for  this  resource.  If  there  is  a  finder,  it  is  called  and 
whatever  it  returns  is  used.  Otherwise  the  set  of  existing  objects  is  searched 
for  one  which  satisfies  both  the  checker  (by  default,  is  not  in  use),  and  the 
matcher  (by  default,  was  constructed  with  parameters  equal  to  the  current 
ones) .  If  none  are  found,  the  constructor  is  called  to  create  one.  Finally,  no 
matter  which  of  the  three  routes  yields  an  object,  the  initializer  (if  any)  is 
called  on  it,  and  the  object  is  marked  as  being  in  use. 

deal  locate -resource  resource -name  object 

The  object  is  conceptually  returned  to  the  specified  resource's  free-list,  i.e., 
its  in-use  marker  is  turned  off. 

using-resource  {variable  resource  parameters  ...)  body  ... 

This  macro,  which  calls  allocate-resource  and  deallocate-resource,  is  pre- 
ferred over  calling  those  two  functions  directly.  The  body  forms  are 
evaluated  inside  a  context  where  variable  is  bound  to  an  object  allocated 
from  resource  with  the  specified  parameters.  The  object  is  deallocated  at 
the  end.  An  unwind-protect  is  used  to  guarantee  that  the  object  is  deallo- 
cated before  using-resource  is  exited. 

Now  an  example.  We  define  a  resource  of  2D  arrays,  with  parameters  for  the 
number  of  rows  and  columns,  which  default  to  100  each.  A  matcher  is  provided 
which  accepts  any  array  whose  dimensions  are  at  least  as  great  as  the  given  param- 
eters. (The  default  matcher  would  require  that  the  dimensions  be  exactly  the  same, 
meaning  that  we  would  very  rarely  reuse  an  object.)  And  an  initializer  fills  the 
array  with  0's. 


Section  8.1  Resources  165 


(defresource  sloppy-2D-array  (^optional  (rows  100)  (columns  100)) 
: constructor  (make-array  (list  rows  columns)) 
: matcher  (and  (^  (array-dimension-n  1  object)  rows) 

(^  (array-dimension-n  2  object)  columns)) 
: initializer  (fillarray  object  '(0))) 


And  to  use  our  resource: 

(defun  do-complex-computation  (x  y) 

(using-resource  (temp-array  sloppy-2D-array  x  y) 

(setf  (aref  temp-array  i  j)  ( calculate-value  i  j)) 
..  .)) 

There  are  several  other  built-in  functions  for  dealing  with  resources. 

deallocate-whole-resource  resource-name 

Deallocates  all  allocated  objects  of  the  specified  resource.  Use  with  caution, 
as  it  can  lead  to  allocation  of  objects  which  somebody  else  is  still  using. 

clear-resource  resource-name 

Makes  the  resource  forget  about  all  its  existing  objects.  Future  calls  to 
allocate-resource  will  result  in  creation  of  new  objects.  Useful  if  the 
resource  has  been  changed  so  that  the  old  objects  are  no  longer  usable,  or  if 
some  of  the  old  objects  have  been  damaged. 

map-resource  resource-name  function  &rest  args 

Applies  function  to  each  object  known  about  by  the  resource.  The  argu- 
ments to  function  will  be:  the  object,  the  value  of  in-use-p  for  the  object, 
resource-name,  and  any  additional  arguments  as  specified  by  args. 


8.2  Systems 

The  system  facility  provides  a  mechanism  for  keeping  track  of  multiple  files  which 
together  make  up  a  single  program.  The  group  of  files  taken  together  is  defined  to 
be  a  system  with  the  defsystem  macro.  Loading  and/or  compiling  some  or  all  of 
the  files  in  a  system  is  accomplished  via  the  make-system  function. 

The  system  facility  is  far  more  complicated  than  the  resource  facility,  and  not 


166  RANDOM  USEFUL  TOPICS:   RESOURCES  &  SYSTEMS  Chapter  8 


necessarily  very  well-designed  ("hairier  than  a  breadbox,"  in  the  local  parlance).  It 
is  supposed  to  be  completely  redone  in  a  forthcoming  Symbolics  software  release,  so 
it's  probably  not  worth  your  trouble  to  learn  the  more  difficult  features  just  now. 
We'll  talk  about  some  of  the  basic  features;  just  enough  for  you  to  be  able  to  use 
systems  for  your  own  programs. 

The  documentation  on  systems  is  Part  II  of  volume  4,  and  is  also  quite  extensive 
but  not  necessarily  very  well-designed,  so  this  portion  of  the  notes  will  follow  the 
manual  less  closely  than  the  resource  section  did. 

Here  is  a  typical  call  to  defsystem: 

(def system  bar 

( : pathname-default    "q : >george> " ) 

(: module   reader-macros    "rdmac") 

(: module   other-macros    "macro") 

(: module   main-program   "main"    "commands") 

( :compile-load  reader-macros) 

( :compile-load  other-macros    (:fasload  reader-macros)) 

( :compile-load  main-program 

(rfasload  reader-macros   other-macros))) 

All  four  files  involved  are  in  the  "george"  directory  on  host  "q."  They  are  divided 
into  three  modules:  reader-macros  and  other-macros,  which  consist  of  one  file 
each,  and  main-program,  which  contains  two  files.  The  reason  for  this  particular 
division  is  that  it  reflects  the  dependencies  among  the  files,  as  specified  in  the 
:  compile -load  clauses.  Each  :compile-load  clause  states  that  the  files  in 
the  specified  module  should  be  compiled  if  necessary  (if  the  newest  source  file  is 
more  recent  than  the  newest  object  file),  and  then  loaded  if  necessary  (if  the  newest 
object  file  is  more  recent  than  the  last  one  to  have  been  loaded),  possibly  subject  to 
certain  dependencies. 

The  reader-macros  module  (file  "rdmac")  does  not  depend  on  any  other  modules. 
The  other-macros  module  (file  "macro"),  on  the  other  hand,  does  depend  on 
reader-macros.  The  (rfasload  reader-macros)  dependency  for  other- 
macros  means  that  the  file(s)  in  reader-macros  have  to  be  loaded  before  those  in 
other-macros  may  be  compiled  or  loaded.  The  reason  is  presumably  that  the  file(s) 
in  other-macros  contain  calls  to  macros  defined  in  reader-macros,  which  must  be 
loaded  for  the  calling  functions  in  other-macros  to  compile  correctly.  The  files  in 
main-program  are  dependent  on  both  the  other  two  modules.  Presumably  they  con- 
tain calls  to  macros  defined  in  both  reader-macros  and  other-macros,  and  so  require 
that  both  modules  be  loaded  before  main-program  may  be  compiled. 


Section  8.2  Systems  167 


Once  the  system  "bar"  has  been  defined  in  this  manner,  it  can  be  loaded  and/or 
compiled  with  make-system,  (make-system  'bar)  will  load  any  files  that  need 
to  be  loaded,  without  doing  any  compilation.  (make-system  'bar  : com- 
pile) will  first  do  any  compilations  that  are  needed,  and  then  do  any  loading  that 
is  necessary.  By  default,  make-system  asks  for  confirmation  before  actually  doing 
any  compiling  or  loading. 

One  bit  of  terminology:  the  operation  of  compiling  or  loading  an  individual  file  is 
called  a  transformation.  So  a  defsystem  could  be  seen  as  defining  what  transforma- 
tions a  system  is  composed  of,  and  a  make-system  as  a  command  to  see  which  of 
the  transformations  are  necessary,  and  to  carry  them  out. 

Now  we'll  go  into  some  more  of  the  various  options  for  defsystem  and  make-system. 
Many  will  be  skipped  entirely. 

For  defsystem: 

We've  already  seen  rpathname-default,  : module,  and  :compile-load. 

:component-systems 

The  mechanism  for  including  other  defined  systems  as  parts  of  this  one. 
What  follows  the  keyword  is  a  list  of  systems.  When  a  make-system  is  done 
on  this  system,  it  will  also  be  done  on  each  of  the  component  systems.  By 
default,  the  transformations  for  this  system  will  be  performed  before  the 
transformations  for  each  of  the  component  systems.  (Yes,  that  seems  wrong 
to  me,  too.)  But  the  default  ordering  can  be  overridden.  If  some  of  the 
local  transformations  depend  on  having  the  component  systems  done  first, 
you  can  use  (:  do -components  nil).  Put  it  at  any  position  in  the  body 
of  the  defsystem,  and  the  transformations  of  the  component  systems  will  be 
performed  at  a  time  corresponding  to  the  chosen  position  in  relation  to  the 
local  system's    :  compile- load  transformations. 

:package 

Specifies  a  package  in  which  the  transformations  are  to  be  performed,  over- 
riding any  package  specifications  in  the  attribute  lists  of  the  individual  files. 

:patchable 

Allows  the  system  to  be  patched*    (incrementally  updated).   Appropriate  for 


PATCH 

1.  noun.  A  temporary  addition  to  a  piece  of  code,  usually  as  a  quick-and-dirty  remedy  to  an 
existing  BUG  or  MISFEATURE.  A  patch  may  or  may  not  work,  and  may  or  may  not  eventu- 
ally be  incorporated  permanently  into  the  program. 


168  RANDOM  USEFUL  TOPICS:   RESOURCES  &  SYSTEMS  Chapter  8 


large  systems  which  are  to  be  distributed  to  many  users.    The  latest  patches 
for  a  patchable  system  may  be  loaded  with  the  load-patches  function. 

And  for  make-system: 

(Recall  that  the  :compile  keyword  must  be  specified  for  any  compilations  to  occur. 
By  default,  only  loading  is  done.) 

:noconfirm 

Assumes  a  yes  answer  for  the  questions  make-system  would  otherwise  ask 
before  performing  transformations. 

:print-only 

Performs  no  transformations  at  all;  just  prints  information  about  which 
transformations  would  need  to  be  done. 

:version 

Loads  a  particular  version  of  a  patchable  system.    There  are  many  different 
ways  to  specify  which  version  —  see  the  documentation. 

One  last  issue  remains  with  respect  to  systems.  Since  make-system  only  works 
after  the  corresponding  defsystem  has  been  evaluated,  it's  important  to  have  a  con- 
venient way  to  get  the  defsystem  done.  Knowing  what  file  it's  in  and  loading  that 
file  manually  before  doing  a  make-system  for  the  rest  is  not  convenient.  For- 
tunately, there  is  something  better.  Whenever  make-system  is  called  on  an 
unknown  system,  i.e.,  one  for  which  a  defsystem  has  not  yet  been  done,  make- 
system  looks  in  a  predetermined  place  for  a  file  to  help  it  out.  If  there  is  a  file 
named  "sys:  site;  system -name. system"  (a  logical  pathname  whose  physical  transla- 
tion depends  on  your  site),  make-system  will  first  load  that  file,  and  then  try  to 
make  the  system. 

The  file  should  contain  either  the  defsystem  itself,  or  a  call  to  si:set-system-source- 
file,  which  will  tell  make-system  what  file  does  contain  the  defsystem.  The  two 
arguments  to  si:set-system-source-file  are  the  name  of  the  system  and  the  file  where 
the  system  definition  may  be  found.  If  you're  the  only  person  likely  to  be  using  the 
system,  another  idea  would  be  to  put  the  call  to  si:set-system-source-file  in  your 
login  init  file,  thus  eliminating  the  need  to  put  a  special  file  in  the  "sys:  site;" 

2.   verb.    To  fix  something  temporarily;  to  insert  a  patch  into  a  piece  of  code.    See  KLUGE 
AROUND. 

(The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  at) 


Section  8.2  Systems  169 


directory. 


170  RANDOM  USEFUL  TOPICS:  RESOURCES  &  SYSTEMS         Chapter  8 


8.3  Problem  Set  #8 

Questions 

1.  Find  out  about  def window  -resource.  It's  used  many  times  in  the  file  "sys: 
window;  sysmen",  which  contains  the  code  for  the  system  menu.  It's  also 
used  in  the  "Smiling  Face"  example,  "sys:  examples;  smile".  (If  you  have 
Release  5  documentation,  you  can  find  a  description  of  this  example,  includ- 
ing a  few  comments  on  def  window -resource,  in  WINDEX).  Now  think  of 
some  sort  of  window  for  which  it  would  be  useful  to  have  a  resource,  define  it 
with  defwindow-resource,  and  use  it. 

2.  Look  through  the  "sys:  site;"  directory.  Pay  close  attention  to  the  system 
definition  files  and  the  logical  host  definition  files.  (Recall  that  system 
definitions  are  by  default  found  in  "sys:  site;  sys -name. system'''  and  logical 
host  definitions  in  "sys:  site;  host -name. translations" .  Note  also  that  if  the 
"sys:"  logical  host  happens  to  translate  at  your  site  to  a  UNIX  system  with  14 
character  limit  on  filenames,  then  "sys-name.system"  will  be  translated  to 
"sys- name. sy"  and  "host -name. translations"  to  "host -name. Id".) 

Most  of  the  system  def  files  will  probably  not  directly  include  the  defsystem, 
but  will  have  a  call  to  si:set-system-source-file,  specifying  some  other  file  as 
the  system  source  file.  Track  down  a  few  of  these  pointers,  and  examine  the 
defsystems.  (Keep  in  mind  that  if  si:set-system-source-fiIe  uses  a  logical 
pathname,  the  logical  host  must  be  defined  with  fs:make-logical-pathname- 
host  before  you  can  find  the  file.)  Assure  yourself  that  you  understand  how 
it  is  that  make-system  can  find  the  defsystem  for  a  new  system.  (You  might 
want  to  look  at  the  source  code  and  see  how  make-system  calls  find-system- 
named,  which  calls  maybe-reload-system-declaration,  which  calls  make- 
system-site-file-pathname.) 


Section  8.3  Problem  Set  #8  171 


Solutions  (roughly  speaking) 

There  isn't  much  to  say  about  this. 

Let's  consider  what  happens  if  you  do  (make -system  'ip-tcp)  on  a 
machine  that  so  far  knows  nothing  about  "ip-tcp."  Since  a  system  named 
"ip-tcp"  has  not  been  defined,  make-system  will  look  in  the  "sys:  site;"  direc- 
tory for  a  file  named  "ip-tcp.system".  At  my  site,  the  logical  pathname  "sys: 
site;  ip-tcp.system"  translates  to  the  physical  pathname  "l:>sys-6> site >  ip- 
tcp.system".  Having  found  that  file,  make-system  will  load  it.  Here's  what's 
in  the  file: 

;;;    -*-  Mode:    LISP;    Package:    USER;    Base:    10   -*- 

( f s :make-logical-pathname-host   "IP-TCP" ) 

(si: set-system-source-file    "IP-TCP"    "IP-TCP:    IP-TCP;    SYSTEM") 

The  second  form  tells  make-system  where  to  find  the  defsystem  for  ip-tcp. 
But  the  file  is  specified  as  a  logical  pathname,  using  host  "ip-tcp,"  which  is 
not  yet  defined.  Thus  the  necessity  of  the  first  form,  the  fs:make-logical- 
pathname-host.  Recall  that  this  function,  when  given  an  unknown  host,  also 
has  a  specific  place  to  look  for  a  file  to  define  the  logical  host:  "sys:  site;  ip- 
tcp.translations".  At  my  site  again,  that  translates  to  "l:>sys-6>site>ip- 
tcp.translations".  So  as  part  of  the  evaluation  of  (fs:make-logical-pathname- 
host  "ip-tcp"),  that  file  will  be  (recursively)  loaded.   And  here's  what's  in  it: 

;;;  -*-  Package:  USER;  Base:  10;  Mode:  LISP  -*- 

( f s : set-logical-pathname-host 
"IP-TCP" 

: physical-host  "L" 
translations  '(("IP-TCP;"  ">sys-6>ip-tcp>" ) 

("IP-TCP; PATCH;"  ">sys-6>ip-tcp>patches>" ) ) ) 

Now  things  begin  to  bottom  out.  This  form  defines  the  logical  host  "ip-tcp," 
and  specifies  which  directories  on  physical  host  "1"  (Laphroaig,  one  of  our 
lisp  machines)  the  logical  pathnames  should  translate  to.  As  the  loading  of 
this  file  is  completed,  the  call  to  fs:make-logical-pathname-host  will  also 
return,  and  we  continue  on  to  the  si:set-system-source-file.  But  now  the  logi- 
cal pathname  "ip-tcp:  ip-tcp;  system"  is  meaningful,  and  translates  to 
"l:>sys-6>ip-tcp> system".  So  make-system  is  now  informed  as  to  which 
file  contains  the  defsystem  for  ip-tcp,  and  proceeds  to  load  it.    Here's  what's 


172 


RANDOM  USEFUL  TOPICS:   RESOURCES  &  SYSTEMS  Chapter  8 


in  that  file: 


-*-  Mode:  Lisp;  Package:  TCP;  Base 
DOD  Internet  Protocol  support. 


10 


Symbolics'  copyright  notice 


(def system  ip-tcp 
:name  "IP-TCP") 
:maintaining-sites  :scrc) 
: pathname-default  " IP-TCP :  IP-TCP ; " ) 
:patchable  "IP-TCP:  IP-TCP;  PATCH;") 
: component- systems 

tcp  tcp-service-paths  ip-tcp-applications! 
:module  chaos  "chaos-unc-interf ace" ) 
: module  global  "ip-global") 
:module  main  ("ip"  "ip-routing" ) ) 
:module  ip-protocols  ("icmp"  "udp"  "egp")) 
:compile-load  chaos) 
:compile-load  global) 

:compile-load  main  (:fasload  global)) 
:compile-load  ip-protocols  (:fasload  global)) 
: do -components  (:fasload  global))) 


.  .  .   defsy  stems  for  tcp,  tcp-service-paths,  and  ip-tcp -applications    .  .  . 

There's  all  kinds  of  stuff  at  the  tail  end  of  this  file,  which  is  a  perfectly  legiti- 
mate short-cut.  We  can  assume  that  it  will  all  be  read  the  first  time  someone 
does  a  (make-system  'ip-tcp).  But  the  crucial  part  is  that  this  file 
must  contain  the  defsystem  for  ip-tcp,  which  you  can  see  above.  Once  the 
loading  of  the  file  is  complete,  make-system  will  continue.  It  now  knows  how 
the  ip-tcp  system  is  defined,  and  can  proceed  to  load  the  files  which  compose 
the  system.  The  filenames  are  all  specified  with  ip-tcp  logical  pathnames,  but 
that's  okay  since  we've  already  defined  the  ip-tcp  logical  host. 

This  sort  of  bootstrapping  may  seem  awfully  baroque,  but  notice  that  the 
whole  mess  can  be  transferred  to  some  other  site  with  a  minimum  of  effort. 
The  only  line  of  code  that  would  need  to  be  changed  is  : physical-host 
"L"  in  the  "sys:  site;  ip-tcp.translations"  file. 


Chapter  9 

SIGNALING   AND  HANDLING  CONDITIONS 


9.1  Overview 

The  material  for  this  chapter  comes  entirely  from  Part  XI  of  volume  2  of  the  Sym- 
bolics documentation. 

An  event  is  some  set  of  circumstances  a  running  program  can  detect.  Some  events 
are  classified  as  errors,  but  not  all  are.  Division  by  zero  is  an  event  which  is  an 
error.  When  an  event  occurs,  the  program  reports  that  fact,  and  finds  some  user- 
supplied  code  to  execute  as  a  result. 

The  reporting  process  is  called  signaling,  and  the  user-supplied  code  which  subse- 
quently assumes  control  is  a  handler.  The  system  software  includes  default 
handlers  for  a  standard  set  of  events. 

The  mechanism  for  reporting  an  event  relies  on  flavors.  Each  class  of  events 
corresponds  to  a  flavor,  called  a  condition.  Signaling  is  more  fully  described  as  sig- 
naling a  condition,  which  involves  creating  a  condition  object  (an  instance  of  the 
appropriate  flavor).  When  division  by  zero  occurs  and  is  signalled,  the  condition 
object  created  is  an  instance  of  the  flavor  sys:divide-by-zero.   The  instance  variables 


174  SIGNALING  AND  HANDLING  CONDITIONS  Chapter  9 


of  the  condition  object  will  contain  information  about  the  event,  including  what 
string  to  use  if  an  error  message  becomes  necessary. 

Each  handler  is  defined  to  be  applicable  only  for  a  particular  flavor  of  condition 
object.  It  can  be  used  only  when  the  condition  signalled  is  an  instance  of  that 
flavor,  or  one  built  on  it.  The  set  of  conditions  a  handler  can  handle  is  thus  deter- 
mined by  the  flavor  inheritance  mechanism.  Handlers  have  dynamic  scope,  so 
finding  a  handler  to  invoke  for  a  given  condition  involves  stepping  through  the  stack 
and  grabbing  the  first  handler  which  is  applicable  to  that  condition. 

There  are  several  kinds  of  actions  a  handler  can  take.  It  may  instruct  the  program 
to  continue  past  the  point  where  the  condition  was  signalled,  possibly  after  correct- 
ing the  circumstances  that  led  to  the  condition  being  signalled.  This  is  called 
proceeding.  Or  it  may  unwind  the  stack  all  the  way  to  the  point  where  the  handler 
was  bound,  flushing  the  pending  operations.  (This  behavior  is  essentially  equivalent 
to  what  you'd  get  with  a  catch  in  place  of  the  handler,  and  a  throw  —  with  the 
correct  tag  —  in  place  of  the  signaling  of  the  condition.)  Or  it  may  partially 
unwind  the  stack  to  some  intermediate  point  and  reexecute  from  there.  This  kind 
of  handler  is  called  a  restart  handler. 

There  are  three  ways  to  customize  the  condition  mechanism: 

•  Defining  handlers  for  existing  flavors  of  conditions  which  may  be  signalled  by 
the  system  code. 

•  Signaling  existing  flavors  of  conditions  within  your  code,  which  may  invoke  the 
system's  default  handlers  or  ones  that  you've  written. 

•  Defining  new  flavors  of  conditions. 


9.2  A  Few  Examples 

(condition-case  () 
(//  a  b) 
( sys : divide-by-zero  *inf inity* ) ) 

This  form  binds  a  handler  for  the  sys:divide-by-zero  condition,  and  evaluates  ( // 
a  b)  in  that  context.  If  the  division  finishes  normally,  its  value  is  returned  from 
the  condition-case.  But  if  b  turns  out  to  be  zero,  the  sys:divide-by-zero  condition  is 
signalled,  and  our  handler  is  invoked,  which  simply  causes  the  condition-case  to 
return  the  value  of  the  symbol   *  infinity*. 

(def flavor  block-wrong-color  ()  (error)) 


Section  9.2  A  Few  Examples  175 


(def method  (block-wrong-color  : report)  (stream) 

(format  stream  "The  block  was  of  the  wrong  color.")) 

This  defines  a  new  error  condition.  (To  define  a  condition  which  is  not  to  be 
treated  as  an  error,  build  it  on  the  flavor  condition  rather  than  error.)  The 
: report  method  is  required.  If  your  program  now  executes  (error  'block- 
wrong-color),  your  new  condition  will  be  signalled.  If  there  are  no  handlers 
currently  bound  for  this  condition,  a  default  handler  will  cause  an  entry  into  the 
debugger  and  use  the  :  report  method  to  generate  the  error  message.  This  par- 
ticular error  message,  however,  is  not  terribly  informative.  It  would  be  nice  to 
know  which  block  had  the  wrong  color,  and  what  color  it  had.   Here: 

(def flavor  block-wrong-color  (block  color)  (error) 
: initable-instance-variables 
: gettable-instance-variables ) 

(def method  (block-wrong-color  : report)  (stream) 
( format  stream 

"The  block  ~S  was  ~S,  which  is  the  wrong  color." 
block  color) ) 

Now  that  we've  added  the  block  and  color  instance  variables,  we  can  do  some- 
thing like 

(error  'block-wrong-color  : block  the-bad-block 

: color  the-bad-color ) 

which  will  initialize  the  instance  variable  as  specified,  and  thus  allow  the  :  report 
method  to  get  at  that  information. 

Another  function  which  may  be  used  to  signal  conditions  is  signal.  It  has  the  same 
syntax  as  error,  but  may  be  used  with  any  flavor  of  condition,  whereas  error  is  re- 
stricted to  use  with  error  conditions,  i.e.,  conditions  built  on  the  flavor  error  (which 
is  indirectly  built  on  the  base  flavor  condition,  via  the  intermediate  flavor 
dbg:debugger-condition) .  There  are  two  additional  differences,  signal  allows 
handlers  to  proceed  the  condition,  and  error  does  not.  (Thus  error  is  guaranteed 
never  to  return  to  its  caller.)  And  when  called  on  a  simple  condition  {i.e.,  one  not 
built  on  dbg:debugger-condition,  as  the  flavor  error  is) ,  signal  returns  nil  if  there  are 
no  handlers  currently  bound  for  the  condition.  (This  is  actually  more  a  difference 
in  the  behavior  of  different  flavors  of  condition  than  a  difference  in  the  behavior  of 
the  functions  signal  and  error,  but  since  error  can't  be  used  with  simple  conditions, 
it  works  as  well  to  think  of  it  as  related  to  the  function  used.)    If  you  signal  any 


176  SIGNALING  AND  HANDLING  CONDITIONS  Chapter  9 


condition  built  on  dbg:debugger-condition,  with  either  signal  or  error,  and  there  are 
no  handlers  bound  for  that  condition,  you  always  end  up  in  the  debugger. 

The  function  most  frequently  chosen  for  signaling  is  actually  neither  of  these,  but 
rather  ferror.  It's  used  to  signal  an  unproceedable  error  when  you  don't  particu- 
larly care  which  condition  is  utilized,  (ferror  eventually  calls  error,  with  a  condi- 
tion flavor  of  ferror.)  It  allows  you  to  specify  a  format  control  string  and  argu- 
ments to  be  used  to  construct  the  error  message. 

The  macros  check-arg  and  check-arg-type  are  also  very  handy  for  signaling  an 
error  in  case  a  function  has  been  sent  inappropriate  arguments. 


9.3  More  on  Handlers 

The  following  is  (I  believe)  a  complete  list  of  the  macros  provided  for  convenient 
binding  of  handlers:  ignore-errors,  condition-case,  condition-case-if,  condition-bind, 
condition-bind-if,  condition-bind-default,  condition-bind-default-if,  condition-call, 
and  condition-call-if.    We  will  discuss  four  of  the  nine. 

ignore-errors  body... 

This  one's  easy.  It  binds  a  handler  which  handles  absolutely  every  kind  of 
error  condition  (not  simple  conditions)  and  does  absolutely  nothing.  Upon 
seeing  the  error,  the  ignore-errors  form  returns.  There  will  be  no  indication 
that  the  error  ever  occurred  (except,  of  course,  that  any  code  within  the 
ignore-errors  following  the  error  will  not  have  been  executed),  ignore-errors 
is  intended  to  replace  the  older  forms  errset  and  catch-error. 

condition-case  (vars...)  form  clauses... 

form  is  evaluated  in  a  context  with  handlers  bound  as  specified  in  clauses. 
If  form  returns  without  signaling  any  conditions,  the  condition-case  also 
returns  (subject  to  one  exception  —  see  below).  If  a  condition  is  signalled, 
the  clauses  are  checked  for  a  handler  bound  for  that  condition.  If  one  is 
found,  the  rest  of  that  clause  tells  how  to  handle  the  condition.  If  a  condi- 
tion is  signalled  for  which  the  condition-case  has  not  bound  any  handlers, 
the  signal  continues  up  the  stack. 

Each  clause  is  a  list  whose  car  is  the  name  of  a  condition  flavor  (or  list  of 
condition  flavors)  and  whose  cdr  is  a  list  of  forms  to  evaluate.  If  a  condition 
is  signalled  matching  the  flavor (s)  (i.e.,  equal  to  it  or  built  on  it)  specified  in 
a  clause,  the  "handler"  consists  of  executing  the  forms  in  the  dynamic 
environment  of  the  condition-case,  not  the  environment  where  the  signal 
occurred.    That  is,  the  stack  is  automatically  unwound  before  the  handler  is 


Section  9.3  More  on  Handlers  177 


executed.  As  a  result,  the  handler  may  not  proceed  the  condition.  While 
the  handler  is  running,  the  first  symbol  in  vars  will  be  bound  to  the  condition 
object. 

As  a  special  case,  the  car  of  the  last  clause  may  be  :  no-error.  Then  if 
no  condition  is  signalled  during  execution  of  the  body,  instead  of  returning 
form's  return  values,  the  vars  will  be  bound  to  those  values,  the  mo- 
error  forms  will  be  evaluated  in  that  context,  and  condition-case  will 
return  whatever  they  return. 

This  example  is  essentially  equivalent  to    ( ignore-errors    (do-this)  ): 

(condition-case  () 
(do-this) 
(error  nil) ) 

And  this  one  uses  the  condition  object: 

(condition-case  (e) 

(time rparse  string) 
(time: parse-error  (format  error-output 

"-A,  using  default  time  instead." 
e) 
♦default-time*) ) 

condition-bind  bindings  body... 

Condition-bind  provides  similar  functionality  to  condition-case,  with  the 
additional  capability  of  proceeding  from  conditions.  Each  binding  in  the  list 
of  bindings  is  a  list  of  two  elements,  the  name  of  a  condition  flavor  (or  list  of 
flavors),  and  a  form  which  produces  a  handler  function.  The  form  is  typi- 
cally a  quoted  symbol,  with  the  symbol  being  given  a  function  definition 
elsewhere.  But  the  form  may  also  be  a  lambda  expression.  The  body  con- 
sists of  any  number  of  forms.  If  a  condition  is  signalled  during  the  evalua- 
tion of  the  body,  the  bindings  are  searched  just  as  with  condition-case.  If  a 
match  is  found,  the  handler  function  is  called  with  one  argument,  the  condi- 
tion object.  The  handler  runs  in  the  dynamic  environment  in  which  the 
error  occurred;  unlike  with  a  condition-case,  the  stack  is  not  unwound. 

The  handler  function  has  three  options.  It  may  return  nil  to  indicate  that 
it  doesn't  wish  to  handle  the  condition  after  all.  (The  search  will  then  con- 
tinue for  a  willing  handler.)  It  may  use  throw  to  unwind  the  stack  to  some 
outer  catch.  Or  it  may  proceed  the  condition  by  returning  a  non-nil  value. 
There  are  several  things  to  keep  in  mind  if  you  wish  to  proceed  a  condition. 
First,  the  condition  must  be  of  a  type  which  is  proceedable;  second,  the 


178  SIGNALING  AND  HANDLING  CONDITIONS  Chapter  9 


condition  must  have  been  signalled  with  signal,  rather  than  with  error;  and 
third,  the  handler  should  send  the  condition  the  :  proceed  message  (with 
an  appropriate  argument)  and  return  whatever  values  the  :  proceed 
method  returns,  because  the  :  proceed  method  may  decline  to  actually 
proceed  and  return  nil,  in  which  case  the  handler  should  also  return  nil. 

Apart  from  being  able  to  proceed  conditions,  the  other  advantage  of  running 
in  the  environment  where  the  condition  was  signalled  is  that  you  may  exam- 
ine the  stack.  A  handler  might  choose  from  among  its  three  options  accord- 
ing to  what  it  finds  on  the  stack,  or  it  might  print  some  message  whose  con- 
tents is  determined  by  the  state*  of  the  stack.  Section  63.4  ("Application: 
Handlers  Examining  the  Stack")  discusses  the  functions  which  are  available 
for  this  purpose. 

condition -bind -default  bindings  body... 

Beyond  the  regular  bound  handlers,  you  can  also  define  default  handlers, 
with  condition-bind-default.  The  list  of  current  default  handlers  is  checked 
only  after  all  the  bound  handlers  have  declined  to  handle  a  condition.  Thus 
by  setting  up  a  default  handler  you  can  allow  outer  bound  handlers  to  take 
precedence  over  your  handler,  but  still  have  your  handler  invoked  if  there 
are  no  appropriate  bound  handlers.  (See  chapter  65,  "Default  Handlers  and 
Complex  Modularity.") 


9.4  Restart  Handlers 

There  are  several  macros  for  establishing  restart  handlers.    Here's  an  example 
taken  from  the  chaosnet  code: 

(defun  connect  (address  contact-name 

^optional  (window-size  default-window-size) 
(timeout  (*  10.  60 . ) ) 


STATE  noun. 

Condition,  situation.  Examples:  "What's  the  state  of  your  latest  hack?"  "It's  WINNING 
away."  "The  SYSTEM  tried  to  read  and  write  the  disk  simultaneously  and  got  into  a  totally 
WEDGED  state." 

A  standard  question  is  "What's  your  state?"  which  means  "What  are  you  doing?"  or  "What 
are  you  about  to  do?"  Typical  answers  might  be  "I'm  about  to  GRONK  OUT"  or  "I'm 
hungry." 

Another  standard  question  is  "What's  the  state  of  the  world?"  meaning  "What's  new?"  or 
"What's  going  on?" 

(The  Hacker's  Dictionary,  Guy  L.  Steele,  Jr.,  et  at) 


Section  9.4  Restart  Handlers  179 


&aux  conn  real-address    (try   0)) 
( error-restart 

( connection-error 

"Retry  connection  to    -A  at   -S  with   longer   timeout" 
address   contact-name) 
forms... )  ) 

This  function  evaluates  forms  and  returns  the  last  value  if  successful.  But  if  the 
debugger  assumes  control  as  a  result  of  a  chaosreonnection-error  condition  during 
the  evaluation,  the  user  will  be  given  the  opportunity  to  restart  by  typing  one  of  the 
super  keys.   The  debugger  printout  will  include  a  line  that  looks  something  like 

s-A:      Retry  connection  to   SCRC  at   FILE    1   with   longer   timeout 

If  the  user  then  types  s-A  the  body  of  the  error-restart  will  be  executed  again  from 
the  beginning.  Now  the  full  descriptions  of  two  of  the  macros  that  may  be  used  to 
establish  restart  handlers: 

error-restart  {condition -flavor  format  -string  format-args. . . )  body . . . 

This  form  establishes  a  restart  handler  for  condition-flavor  and  then  evalu- 
ates the  body.  If  the  handler  is  not  invoked,  error-restart  returns  the  values 
produced  by  the  last  form  in  the  body  and  the  restart  handler  disappears. 
When  the  restart  handler  is  invoked,  control  is  thrown  back  to  the  dynamic 
environment  inside  the  error-restart  form  and  execution  of  the  body  starts 
all  over  again,  condition-flavor  is  either  a  condition  or  a  list  of  conditions 
that  can  be  handled,  format-string  and  format-args  are  a  control  string 
and  a  list  of  arguments  to  be  passed  to  format  to  construct  a  meaningful 
description  of  what  would  happen  if  the  user  were  to  invoke  the  handler. 
format  args  are  evaluated  when  the  handler  is  bound.  The  debugger  uses 
these  values  to  create  a  message  explaining  the  intent  of  the  restart  handler. 

error-restart-loop  (condition  -flavor  format  -string  format  -  args. ..)  body. . . 

Similar  to  error-restart,  but  with  an  infinite  loop.  If  the  handler  is  not 
invoked,  instead  of  returning  the  body  is  reexecuted.  (The  loop  may  be 
exited  with  return.)  This  form  is  commonly  used  in  the  top-level  function 
for  a  process,  with  condition-flavor  being  (error  sys:abort). 


9.5  More  on  Proceeding 

Chapter  68  ("Proceeding")  is  a  cogent  five-page  discussion  of  what  is  involved  in 
programming  proceedable  errors.  I  recommend  reading  it.  I  will  include  just  a  few 
highlights  here. 


180  SIGNALING  AND  HANDLING  CONDITIONS  Chapter  9 


For  proceeding  to  work,  two  conceptual  agents  must  agree: 

•  The  programmer  who  wrote  the  program  that  signals  the  condition 

•  The  programmer  who  wrote  the  condition-bind  handler  that  decided  to  proceed 
from  the  condition,  or  else  the  user  who  told  the  debugger  to  proceed. 

The  signaller  signals  the  condition  and  provides  a  set  of  alternative  proceed  types. 
The  handler  chooses  from  among  the  proceed  types  to  make  execution  proceed.  A 
proceed  type  is  defined  by  giving  the  condition  flavor  a  .'proceed  method. 
(:  proceed  methods  are  combined  using  the  :  case  combination  type,  so  that  one 
flavor  may  have  any  number  of  :  proceed  methods,  each  defining  a  different  type. 
The  first  argument  to  the  method  dictates  which    :  case  is  to  be  called.) 

The  body  of  the  :  proceed  method  can  do  anything  it  wants,  generally  trying  to 
repair  the  state  of  things  so  that  execution  can  proceed  past  the  point  at  which  the 
condition  was  signalled.  It  may  have  side-effects  on  the  environment,  and  it  may 
return  values  (which  will  then  be  returned  by  signal)  so  that  the  function  that 
called  signal  can  try  to  fix  things  up.  Its  operation  is  invisible  to  the  handler;  the 
signaller  is  free  to  divide  the  work  between  the  function  that  calls  signal  and  the 
:  proceed  method  as  it  sees  fit. 

Review:  suppose  a  condition  is  signalled  for  which  a  handler  has  been  bound  with 
condition-bind.  The  handler  function  is  called  with  one  argument,  the  condition 
object,  and  it  may  throw  to  some  tag,  or  return  nil  to  decline  to  handle  the  condi- 
tion, or  try  to  proceed  the  condition.  To  proceed,  it  must  first  determine  which 
proceed  types  are  valid  for  the  condition  object.  This  must  be  done  at  run-time 
because  condition  objects  can  be  created  that  do  not  handle  all  of  the  proceed  types 
for  their  condition  flavor,  via  the  :proceed-types  init  option,  and  because  con- 
dition objects  created  with  error  instead  of  signal  will  have  no  proceed  types.  The 
handler  may  use  the  :proceed-types  message  to  get  a  list  of  the  available 
proceed  types,  or  it  may  use  the  :proceed-type-p  message  to  check  a  particu- 
lar candidate.  Having  chosen  a  proceed  type,  the  handler  sends  the  condition 
object  a  :  proceed  message  with  one  or  more  arguments.  The  first  argument  is 
the  proceed  type,  and  the  rest  are  the  arguments  for  that  proceed  type.  Sending 
the  :  proceed  message  should  be  the  last  thing  the  handler  does.  It  should  then 
return  immediately,  propagating  the  values  from  the  :  proceed  method  back  to 
its  caller.  Determining  the  meaning  of  the  returned  values  is  the  business  of  the 
signaller  only;  the  handler  should  not  look  at  or  do  anything  with  these  values. 

The  signal-proceed-case  macro  provides  a  convenient  way  to  signal  a  proceedable 
condition,  choose  which  of  the  defined  proceed  types  for  that  flavor  of  condition 
should  be  considered  available  to  the  handlers,  and  specify  separate  actions  to  take 


Section  9.5  More  on  Proceeding  181 


for  each  of  the  proceed  types  (after  the    : proceed  method  returns). 


Chapter   10 

THE  MOVING  ICONS  EXAMPLE 


The  original  version  of  the  moving  icons  example  was  put  together  by  Ken  Church 
for  a  class  he  taught  in  1984.  I've  made  some  cosmetic  modifications,  and  updated 
it  to  take  advantage  of  some  more  recently  written  support  software.  The  basic 
idea  is  that  you  have  a  frame  split  into  two  panes:  a  command  menu  of  icons  the 
user  may  "pick  up"  with  the  mouse,  and  an  initially  empty  pane  where  the  user 
may  drop  icons  that  have  been  picked  up. 

As  before,  if  your  site  has  loaded  the  tape  that  comes  with  the  book,  do  Load 
System  moving-icons  [or  (make-system  ' moving- i cons  )]  to  load  the 
code.  But  this  time,  to  make  a  frame  and  start  the  action,  get  the  system  menu 
and  click  on  Moving  Icons  at  the  lower  right.  Click  left  over  one  of  the  icons  to 
pick  it  up,  move  the  mouse  over  the  main  pane,  and  drop  the  icon  by  clicking  left 
again. 


10.1  General 

It's  my  impression  that  there  are  four  concepts  in  this  short  piece  of  code  which  are 
new:     using    Zmacs-style    command    tables    ("comtabs"),    pop-up    mini-buffers, 


184  THE  MOVING  ICONS  EXAMPLE  Chapter  10 


typeout  windows,  and  changing  the  appearance  of  the  mouse  blinker.  Most  of  the 
dirty  work  involved  in  getting  the  first  three  to  work  is  taken  care  of  by  the  "corn- 
tab"  system  (locally  written  software  which  both  Ken  and  I  have  worked  on).  The 
zwei:window-with-comtab  flavor  captures  most  of  the  fruits  of  this  work,  and  is 
itself  quite  easy  to  use.  Another  portion  of  the  support  code  redefines  many  inter- 
nal editor  functions  for  reading  typein  from  the  mini-buffer  to  also  work  outside  the 
editor,  with  pop-up  mini-buffers. 

A  comtab  associates  characters  with  functions,  so  that  whenever  a  certain  key  is 
pressed  the  corresponding  function  is  called.  In  the  editor,  for  instance.  #\c-F  is 
bound  to  the  function  corn-forward,  which  moves  the  cursor  forward.  ("Charac- 
ters" includes  mouse  characters,  so  functions  may  also  be  bound  to  particular 
mouse  clicks.)  In  addition  to  single  key  commands,  a  comtab  may  include 
extended  commands.  These  are  accessible  via  Meta-X.  You  then  type  in  the  full 
name  of  a  command  to  a  mini-buffer.  (Completion  is  active,  so  you  frequently 
need  only  to  type  a  few  characters.)  If  you're  in  the  editor  proper,  the  permanent 
mini-buffer  at  the  bottom  of  the  screen  is  used.  If  you're  using  the  window-with- 
comtab,  a  temporary  mini-buffer  pops  up. 

The  window-with-comtab  flavor  has  a  comtab  instance  variable,  and  also  includes 
the  flavor  tv:process-mixin.  The  top-level  function  for  the  process  is  a  loop  which 
reads  characters  and  looks  them  up  in  the  window's  own  comtab,  calling  the  func- 
tions that  are  found.  (It  also  does  something  appropriate  if  it  sees  a  blip  instead  of 
a  character.)  All  you  need  do  is  define  the  functions  and  put  them  in  the  comtab. 
By  copying  so  closely  the  mechanism  used  by  the  editor,  we  are  able  to  use  many  of 
the  editor  functions  without  change  (or  with  small  changes),  most  notably  the  on- 
line documentation  features.  The  Help  key  is  active  in  any  window  built  on 
window-with-comtab,  providing  various  functions  for  finding  out  about  the  currently 
defined  commands.  And  a  number  of  extended  commands  have  also  been  brought 
over  from  the  editor,  including  Edit  Key,  Edit  Extended  Command,  Lookup  Key 
Bindings,  Describe  Key  Bindings,  Set  Variable,  and  List  Variables. 

Any  window  built  on  window-with-comtab  will  also  have  a  typeout  window  associ- 
ated with  it.  Just  as  in  the  editor,  if  you  hit  the  Suspend  key,  the  typeout  window 
will  become  exposed,  and  you  will  enter  a  break  loop,  so  that  you  may  type  arbi- 
trary lisp  forms  to  be  evaluated. 

Let's  take  a  look  at  the  code  now. 


Section  10. 1  General  185 


10.2  moving-icons-frame 

We  have  two  panes,  the  command  menu  and  the  main  pane.  The  frame  is  a  bor- 
dered constraint  frame  with  shared  io-buffer,  so  that  the  process  running  in  the 
main  pane  will  see  the  blips  from  the  command  menu.  The  only  new  stuff  is  in  the 
default-init-plist  specified  for  the  menu.  The  most  interesting  is  the  specified  value 
for  :  item-list.  As  in  the  tree  example  of  three  weeks  ago,  we've  used  the 
"general"  item  type.  Each  element  of  the  list,  corresponding  to  one  item  in  the 
menu,  is  a  list  of  five  elements.  The  first  is  the  string  which  will  be  printed  to 
display  the  item  in  the  menu.  As  you  can  see  from  the  form  of  the  loop,  the  string 
will  be  one  character  long  for  every  item,  with  the  character  code  ranging  from  0  to 
127.  Since  each  item  is  of  type  :eval,  the  effect  of  executing  an  item  will  be  to 
evaluate  the  form  following  the  :eval  keyword.  And  the  form  sends  the  main 
pane  the  :  pick-up- icon  message,  with  an  argument  of  the  item's  character 
code.  (It  helps  to  know  that  the  window-with-comtab  code  takes  care  of  binding 
the  variable  zwei:*window-with-comtab*  to  the  object  which  has  the  window-with- 
comtab  mixin,  in  this  case  the  main  pane.)  So  if  I  choose  the  item  in  the  upper  left 
corner  of  the  menu,  the  main  pane  will  receive  a  : pick-up-icon  message  with 
an  argument  of  0. 

The  :rows  init  spec  instructs  the  menu  to  display  its  128  items  in  4  rows  of  32 
each,  implying  that  it  must  do  some  horizontal  spreading.  And  the  :  default- 
font  spec  is  crucial.  Since  the  items  are  really  just  one-character  strings,  the  way 
they  appear  depends  on  what  font  the  menu  uses  for  printing  them.  By  default, 
command  menus  use  a  standard  variable-width  alphabetic  font  called  jess  14.  But 
we've  specified  the  font  named  mouse,  which  happens  to  contain  many  of  the  char- 
acters which  are  used  for  the  mouse  blinker  in  various  situations.  You  could  use 
any  other  font  —  either  an  existing  one  or  one  of  your  own  creation  —  by  changing 
the  :  default-font  spec  (or  by  sending  the  :  set-icon-font  message,  which 
is  done  by  Meta-X  Set  Icon  Font).  You  can  read  about  using  fonts  in  section  12.7 
of  volume  7.  See  also  the  Zmacs  commands  Meta-X  List  Fonts  and  Meta-X 
Display  Font.  For  modifying  a  font  or  creating  a  new  one,  use  the  Font  Editor, 
which  is  described  in  Part  II  of  volume  3. 


10.3  moving-icons-main-pane 

This  flavor  is  built  on  zwekwindow-with-comtab,  with  tv:pane-no-mouse-select-mixin 
added,  to  make  it  a  pane,  and  one  which  will  not  confuse  the  select  menu.  An 
instance  variable  keeps  track  of  the  current  icon.  The  default-init-plist  specifies 
what  comtab  to  use  (*icon-comtab*  is  defined  at  the  end  of  the  file)  and  what  font 
the  window  should  print  with.    This  font  obviously  needs  to  match  the  font  of  the 


186  THE  MOVING  ICONS  EXAMPLE  Chapter  10 


command  menu. 

The  first  two  methods  are  quite  simple.  The  :  set-icon-font  method  sets  the 
default  font  of  the  command  menu  (which  causes  it  to  redisplay  all  the  items  in  the 
new  font)  and  sets  the  window's  own  font-map  to  match  (which  affects  only  subse- 
quent typeout  —  the  current  display  is  left  alone).  The  : pick-up- icon  mes- 
sage, recall,  is  sent  when  a  menu  item  is  executed.  The  method  sets  the  icon- 
character  instance  variable,  and  sends  the  window  the  : mouse-standard- 
blinker  message,  which  we'll  see  has  the  effect  of  making  the  mouse  blinker  look 
like  the  item  which  was  just  chosen. 


10.4  Messing  with  the  mouse  blinker 

The  easiest  way  to  alter  the  appearance  of  the  mouse  blinker  (though  not  the  way 
we  do  it  in  this  example)  is  with  the  function  tv:mouse-set-blinker.  It  has  one 
required  argument  —  a  keyword  symbol  —  and  two  optional  ones.  The  keyword 
tells  what  sort  of  blinker  to  switch  to,  and  the  system  must  already  have  been  told 
how  to  get  a  blinker  of  that  type.  Teaching  the  system  about  new  types  of  blinkers 
is  not  difficult,  but  it's  also  not  necessary  in  this  case,  so  we  don't  need  to  go  into  it. 
The  reason  it's  not  necessary  is  that  there's  already  a  kind  of  blinker  which  is 
sufficiently  flexible  for  our  needs,  and  that  is  the    :  character  blinker. 

This  sort  of  blinker  has  two  instance  variables,  one  specifying  a  font  to  use  and  one 
a  character  code.  The  blinker  draws  itself  as  the  given  character  in  the  given  font. 
So  by  adjusting  the  values  of  the  instance  variables,  a  single  blinker  can  be  made  to 
look  like  any  character  in  any  defined  font.  This  is  exactly  the  reason  for  the 
existence  of  the  "mouse"  font;  most  of  the  various  mouse  blinkers  you're  used  to 
seeing  are  actually  the  same  :  character  blinker,  set  to  varying  characters  in  the 
mouse  font. 

And  finally  we  come  to  the  function  tv:mouse-set-blinker-definition,  which  is  what 
the  example  uses  in  place  of  tv:mouse-set-blinker.  The  former  takes  several  addi- 
tional arguments,  which  allow  you  to  send  an  arbitrary  message  to  the  "new" 
blinker  (which  may  really  be  the  same  object  as  the  old  blinker).  The  message  we 
send  is  :  set-character,  which  takes  two  arguments,  the  new  character  code, 
and  (optionally)  the  font  to  use.  In  our  case  the  character  is  the  value  of  the 
instance  variable  icon-character,  which  will  have  been  set  by  the  :  pick-up- icon 
method,  and  the  font  is  the  main  pane's  current  font  (accessed  via  the  instance 
variable  tv:  current-font),  which  we  have  been  careful  to  make  sure  is  always 
the  same  as  the  menu's  font.  For  a  slightly  different  effect,  type  this  at  a  lisp 
listener: 


Section  10.4  Messing  with  the  mouse  blinker  187 


(tv: mouse-set-blinker-definition  : character  0  0  t  : set-character 
#\M    ' fonts :43vxms) 

The  second  and  third  arguments  to  tv:mouse-set -blinker-definition  specify  the  jc- 
offset  and  y -offset  for  the  blinker.  By  default,  the  offsets  are  0,  meaning  that  the 
blinker  draws  itself  with  its  upper  left  corner  at  the  actual  mouse  position.  Often 
you  would  rather  the  blinker  position  itself  differently,  perhaps  with  its  center  over 
the  real  mouse  position.  That's  when  you  need  to  set  non-zero  offsets.  In  the 
example,  we  use  whatever  offsets  the  previous  blinker  had,  to  minimize  any 
apparent  motion  of  the  mouse  as  we  switch  blinkers.  And  if  you  glance  down  at 
the  : drop-icon  method  you'll  see  we  need  to  adjust  for  the  offsets  again  when 
drawing  the  icon  on  the  main  pane,  so  that  the  icon  is  placed  exactly  under  where 
the  mouse  appears  to  be. 

But  let's  return  to  the  : mouse- standard-blinker  method.  Why  did  I  make 
the  :  pick-up- icon  method  call  this  one  to  change  the  mouse  blinker,  instead  of 
just  including  the  multiple-value-bind  form  directly  in  : pick-up-icon?  And 
why  does  : mouse-standard-blinker  test  whether  icon-character  has  a 
non-nil  value  when  :  pick-up-icon  will  have  just  given  it  one?  The  answer  to 
both  questions  is  that  the  mouse  process  will  occasionally  be  sending  our  window 
the  : mouse-standard-blinker  message,  and  I  want  to  do  something 
appropriate  then  as  well  as  when  : pick-up-icon  sends  the  message.  Exactly 
when  the  mouse  process  sends  : mouse-standard-blinker  is  difficult  to 
explain,  but  a  reasonable  approximation  is  that  it  will  happen  whenever  the  mouse 
crosses  into  the  window.  There  is  a  default  handler  for  :  mouse- standard- 
blinker,  which  our  window  would  have  inherited,  and  its  action  is  simply  to  pass 
the  same  message  up  to  the  window's  superior.  (If  all  of  the  window's  superiors 
also  follow  the  default  route  of  passing  the  message  up,  it  will  eventually  reach 
tv: main- screen,  which  will  restore  the  blinker  to  the  familiar  NNW  arrow  seen 
in  a  lisp  listener.)  But  our  method  supersedes  the  default  one.  If  there  is  no 
current  icon-character,  ours  behaves  just  like  the  default;  if  there  is  an  icon- 
character,  ours  makes  the  mouse  blinker  look  like  the  icon.  Had  I  put  the 
tv:mouse-set-blinker-definition  in  : pick-up-icon  and  kept  the  default  method 
for  : mouse-standard-blinker,  we  would  have  lost  the  special  appearance  of 
the  mouse  blinker  every  time  it  crossed  into  the  main  pane,  including  the  manda- 
tory first  trip  down  from  the  command  menu. 


10.5  The  :drop-icon  method 

Dropping  the  icon  involves  setting  the  cursor  position  to  the  correct  spot,  outputting 
the  character,   resetting   the  icon-character  instance  variable,  and   restoring  the 


188  THE  MOVING  ICONS  EXAMPLE  Chapter  10 


mouse  blinker  to  its  usual  form.  The  only  tricky  step  is  setting  the  cursor  position 
—  the  mouse  position  will  be  provided  in  terms  of  outside  coordinates.  These  must 
be  converted  to  inside  coordinates  by  subtracting  the  margin  widths,  and  then 
corrected  for  the  blinker  offsets. 


10.6  Setting  up  the  comtab 

The  way  to  define  a  command  is  with  the  defcom  macro  (in  the  zwei  package). 
The  first  argument  is  the  name  of  the  command,  which  should  begin  with  "com-". 
Then  there's  a  documentation  string,  which  the  help  key  will  know  how  to  get  at. 
The  third  argument  is  a  list  of  options  which  are  not  relevant  outside  the  editor. 
The  rest  is  the  body  of  the  command.  Note  that  there  is  no  "argument  list";  func- 
tions defined  with  defcom  are  intended  to  look  for  their  arguments  as  the  value  of 
zwei:*numeric-arg*.  Recall  that  "arguments"  to  editor  functions  are  numbers, 
struck  with  the  control  or  meta  keys  down  before  the  main  command  character  is 
pressed.  The  effect  of  the  numeric  control  keys  is  to  bind  *numeric-arg*  appropri- 
ately. 

Executing  a  defcom  just  defines  a  function  and  adds  the  name  of  the  command  and 
its  documentation  to  a  list  of  all  commands,  but  does  not  make  the  command 
usable  —  it  is  not  included  in  any  comtab.  What  puts  the  command  into  a  comtab 
is  the  zwei:set  -comtab  function,  set-comtab  adds  a  list  of  character-command  pairs 
(its  second  argument)  to  an  existing  comtab  (the  first  arg) .  The  third  argument,  if 
present,  is  a  list  of  extended  commands,  i.e.,  commands  that  will  be  accessible  via 
Meta-X.  The  list  should  be  created  with  zwei:make-command-alist  and  may  be 
appended  with  the  extended  command  list  of  some  other  comtab.  A  single  com- 
mand may  appear  in  a  comtab  any  number  of  times,  paired  with  different  charac- 
ters and/or  as  an  extended  command.  And  it  may  simultaneously  appear  in  any 
number  of  different  comtabs. 

The  function  zweirset-comtab-indirection  may  be  used  to  cause  inheritance  from 
another  comtab.  Any  characters  not  found  in  the  current  comtab  will  be  looked  up 
in  the  second  one.  In  particular,  we  need  to  inherit  from  *basic-comtab*  (the  one 
defined  with  window-with-comtab)  the  numeric  argument  commands  and  the  help 
functions. 


10.7  Getting  in  the  System  Menu 

The  last  form  in  the  file  is  what  puts  "Moving  Icons"  in  the  rightmost  column  of 
the    system    menu.     The    function    tv:add-to-system-menu-programs-column    takes 


Section  10.7  Getting  in  the  System  Menu  189 


three  arguments.  The  first,  a  string,  is  what  you  want  to  appear  in  the  menu.  The 
second  is  a  form  to  be  evaluated  should  your  item  be  chosen  from  the  menu.  This 
is  usually  a  call  to  the  function  tv:select-or-create-window-of-flavor,  with  the  one 
argument  being  the  flavor  of  window  you  want  created.  Finally  there's  a  documen- 
tation string,  which  appears  in  the  mouse  documentation  line  whenever  the  mouse  is 
over  your  item  in  the  system  menu. 


10.8  The  Program 


190 


THE  MOVING  ICONS  EXAMPLE 


Chapter  10 


Section  10.8  The  Program  191 


d  5?«  fl-9  *      -a 

o)  -h  =  e  C  >  H  «, 

2  N "  8  B » "  S3 

C  --*  >—  fl  1    ••  —  Q)  0> 

m  u  en*  <u  3  "O 

•§  iS  -H    rH  3  O     C     <1>  O  U 


O  P                              gHH  S    °    °    °  i                                                  6    CO 

1  I  2     L£3  ti3s  3  is:  852*3 e 

&  i     §     *  -  5  a  S  >~  g  2  2  8  *  >  * 

2  •?  Hss  as  »  13?l§? 


£ 


O  0)  o  ^-  -^        .0  3 

+J  5  «S  -P  «« 

0)  C  i-l  +J  0) 

B  . .  iw  <D  T> 

<W  >  4-1  01  •• 

0)  +J  (U  ••  ~ 


192 


THE  MOVING  ICONS  EXAMPLE 


Chapter  10 


0 

Pi 

4-1 
1 

s 

P 

Pi 

C 

o 

CU 

•H 

p 

P 

p 

■iH 

0 

CO   — > 

u 

R7 

^ 

> 

--» 

>^ 

CO 

p 

CO           ^ 

<D      1 

p 

p  "-  — 

CO    CU 

^^ 

0) 

p 

0)    0)  — 

S     CO 

H 

•— » 

JJ 

CO 

cu 

CO    N    0) 

0    Pi 

■H 

c 

4-1 

p 

4-1  -H     N 

E    O 

C 

En 

o 

4-1 

u 

4-1    CO   -H 

E 

z 

4H 

1 

0 

P 

03 
U 

O     1      CO 

cu    * 

Xi    •• 

3 

r      O   — 
CO   Cu  — 

> 

03 

--» 

•H     Pi 

P   -H 

c 

Eh  »     — 

v 

iH 

P 

4-1 

X! 

>> 

P     Ol-rl 

cu 

<D 

2        -* 

c 

■rl 

0) 

4-1 
0 

U 

cu 

l>    P    Cn 
M    03    P 

P  s 

id  n 

E 

O  —  -» 
fa  X  ~ 

p  p 

c 

C 

(0 

Pi  E  <g 

C 

s             --» 

c  c 

•H 

>>  o 

0 

■H     1      E 

-  * 

0 

J   X 

0  o 

p 

rH 

O 

0 

rH    P      1 

*  X 

o 

Z  ^ 

4H  <w 
1      1 

a) 

XI 

4-1 
4-1 

■H 

6 

xi  4h  a 

1       0)     0 

Pi  1 

id    cu 

•H 

H    >    i-i 

w  <d 

5  P 

c 

a 

cu 

0 

P 

X 

(1)    rH    P 

(0 

CU 

w  2   > 

0)    r-l 

o 

■H 

CO 

0) 

I 

10    ••     •• 

4H     Pi 

X! 

J    >H     cu 

C    3 

u 

rH 

0 

X 

P 

0) 

PI     >     > 

•h  g 

P 

OWE 
S  ~  ^ 

—   o3 

•H 

X) 

0 

U 

(0 

0  P  P 

E 

4H 

1 

E 

u 

03 

0 

E 

•>  * 

4H 

p< 

S         co 

— >    Q) 

■d 

cu 

P 

0 

••    4H    4H 

Pi  •• 

0 

w 

tM    P4    — 

p  tj 

,-» 

P 

> 

p 

03 

»-» 

E 

>    4H    4H 

0   -H 

fu 

CO  w 

c    I 

c 

03 

P 

u 

XJ 

POO 

u   cu 

P 

P 

fn 

1    (U  — 

O  P 

o 

■0 

03 

O 

p 

1       1 

•H     S 

Pi 

PI 

& 

a  >i  x 

4-1    0) 

o 

C 

T3 

u 

1 

ID 

»-» 

-O    X    >> 

N 

0 

0 

PQ 

W   Eh 

1      10 

■H 

id 

C 

03 

P 

M 

Pi 

Pi 

P 

4H 

4-1 

w  —  < 

C   •• 

_ 

■P 

(1) 

Xi 

CU 

3 

0 

cu  x  >, 

Pi     Pi 

1 

H 

o 

a 

CO 

CO 

u 

to 

•H 

o 

CO      1       1 

0)    0 

CU 

PI 

Z 

o  *-+ 

3 

i 

<-i 

•H 

_-    CU     0) 

P    O 

XI 

0 

H 

Eh   X   2 

•H     0 

+J 

i 

(V 

XI 

1 

CO     CO 

--» 

P   -H 

P 

o 

S 

2         Cu 

1      C 

c 

x 

CO 

«-~ 

a 

a 

—  pj  pt 

p 

*  JL 

•rl 

1 

H   CU     1 

4j   a) 

0 

u 

0 

4-1 

o 

T3 

0 

4H     0     0 

0) 

o  a 

CO 

1 

S 

1     Q    Eh 

<D  e 

4-1 

■H 

0 

4-1 

•rl 

P 

p 

4H    E    E 

M 

0 

cu 

P 

o 

J    2    W 

(0  » 

1 

a 

E 

0 

P 

03 

•o 

o 

Pi 

CU     P 

tr  0) 

« 

<  t>  o 

? 

p 

•H 

TJ 

P 

•H 

X!   TJ 

Pi 

CO 

h 

yo- 

V 

0) 

0) 

>t  c 

C 

>,—  ~ 

CU 

rH 

p  •• 

03 

i 

o  m 

V   c 

c 

CU 

M 

0) 

•H 

03 

CU 

p 

XI 

XI 

9 

►J  '-'  CO 

C    id 

c 

C 

a 

4-1 

4-1 

P 

c 

4-1     CO 

0 

1 

CO     * 

u 

* 

2 

(0      O,   4-1 

(0 

■H 

id 

4-1 

CU 

CO 

03 

a  4-i  o 

03 

x> 

a  xi 

XI 

w 

O  X  o 

Q,    1 

CO 

a 

rH 

a 

0   X) 

1 

a 

CU 

o  a 

P 

»-« 

p 

o  id 

03 

Pi 

2        U 

1    p 

-rl 

XI 

i 

1 

1 

CU 

cu 

1    u 

03 

rH 

id 

p  p 

p 

P 

HP   — 

C    CD 

tH 

c 

1 

f: 

X 

p 

CO 

c 

XI 

X    0 

Xi 

■H 

X) 

Q    E 

g 

E  O 

S^EH 

•H    D> 

•H 

T) 

■H 

cu 

53 

•H 

—    CO 

U 

Pi 

Pi 

=      0 

o 

0 

z 

<d  •• 

03 

a 

P 

03 

* 

0 

flj 

u 

<d 

o 

4-1 

u 

H 

—  U 

S 

a 

6 

o 

03 

6 

XI 

c 

E 

6 

^~ 

X)   pi 

Pi 

p 

P 

S  I 

1 

1 

En 

=     X        w 

1    u 

03 

O    Tl 

i 

c 

■H 

i 

p 

Pi    o 

0 

cu 

CO 

0  Xi 

Pi  X! 

W 

2  J 

co  o 

a 

CO 

•H 

c 

CO 

•H 

r-i 

CO 

cu 

•H     1 

u 

p 

i 

O   P 

0 

p 

J 

P    P<   W    J 

C   -H 

i 

c 

03 

Pi 

X)  X) 

P 

a 

p 

Xt  P 

•H 

u 

V 

•H    -rH 

CJ 

•H 

a. 

c  o  a  o 

O    P 

p 

0 

u 

P 

0 

1 

1 

O 

0 

u 

1     0) 

03 

to 

r.      S 

•H 

? 

2 

o  fa  s  u 

o  a> 

c 

u 

CU 

CO 

O 

cu 

P 

■H 

o 

03 

0)    CO 

0 

p 

p» 

a  i 

1 

1 

O 

fa 

•h  a 

0 

•H 

P 

•H 

p 

3 

CU 

P 

■H 

P 

pi  •• 

>,  03 

0 

o  ? 

P 

£   U 

fa 

i    3 

4-1 

o 

a) 

CD 

rH 

CO 

CU 

1 

03 

rH 

P 

45 

E 

P    0 

CU 

0 

?  2 

&>  to 

C7> 

ifl 

CO 

&>  P 

03 

1 

a 

Cn  X! 

0)    4H 

o 

XI   XI 

CO 

X) 

•H 

cu  O 

Pi    •• 

P 

C 

u 

0 

Pi 

U 

> 

cu 

n 

Pi 

O 

>   rH 

1 

L  c 

1 

c 

CU 

2  J 

•H     > 

<D 

•H 

03 

0 

•H 

03 

1 

CO 

CO 

•H 

1 

1      0) 

4H 

PI 

4H 

i  "d 

E 

•H 

5 

>    P 

CO 

>  X! 

E 

> 

P 

0) 

0 

> 

C 

0)    CO 

r-{ 

0 

r-t 

o  » 

0 

s 

N 

0 

0 

o 

0 

03 

rH 

0 

> 

0 

o 

rH 

0) 

o 

<U 

o   * 

u 

* 

E    TJ 

e 

1 

exi 

a  e 

p 

E 

o 

ax» 

CO 

•H 

CO 

—  c 

4-1 

c 

4-1 

U 

•H 

•H 

•rl     Pi 

I  "H 

E 

•H 

P 

0) 

r-l 

0 

rH 

P 

> 

T3 

P     CU 

X) 

tr  xi 

0    0) 

0 

0) 

XI 

xi    co 

CD 

xs 

u 

(1) 

n 

C 

H 

p 

fl 

•O 

P 

rH     CO 

C 

p 

Pi 

O    S 

u 

> 

U 

0  -— 

CO 

0 

•H 

CO 

0 

0 

3 

CU 

0 

0 

Pi   — 

cu 

cu 

0) 

4H     N 

4H 

N 

X! 

Xi 

X) 

u 

E 

CO 

X! 

c 

e 

CO 

CO 

CO 

CU 

CU 

P  XI  Xl 

p 

crx» 

+j 

•H 

— 

P 

^-- 

— » 

— - 

"— 

XI   XI 

XI 

XI 

<D     C 

c 

CU 

-p 

a 

CD 

CU 

••    Pi 

PI 

E    0) 

cu 

e 

CU 

0) 

a 

4-1 

E 

4-1 

•rl     CU 

■H 

CU 

<4-l     CO 

CO 

4-1 

CO 

CO 

4-1 

■H 

4-1 

■H 

CU     CO 

CU 

CO 

CD    — 

0) 

0) 

tt) 

>    — 

£ 

T3 

T3 

xi 

•o 

N 

N 

Section  10.8  The  Program  193 


XX 

Ifl 

e 

■o 

a 

0 

s 

o  ^ 

*-+ 

3 

to   * 

a 

C  Xi 

p 

^    0) 

O    fl 

c 

j)  a 

O   P 

0 

a 

h  a 

<4-l 

fl    <0 

0 

1 

p  _ 

Oi  o 

c 

«w  a 

C     I 

0 

I     0 

•H     O 

o 

01     P 

>   -H 

■H 

C  m 

0     01 

1 

0 

£     IT) 

p 

U   co 

=      A 

tt) 

■H    C 

* 

01 

I     0 

XI    •• 

1 

Oi  o 

fl   -H 

a 

C   -H 

P    tt) 

0 

•H 

B   ? 

*-« 

o 

>  Xi 

0    N 

c 

O  P 

O 

0 

v 

6  -d 

1     * 

0 

»    £ 

4)  £1 

•H 

p 

co   nS 

1 

01 

p  tt) 

P   P 

ft 

■H 

0    P 

to  e 

0 

rH 

g 

>     0 

ft  0 

1-1 

id 

g 

HJ    p 

CO    o 

1     1 

1 

13 

iH 

rH     O 
<4-l   -H 

tt)   G 

e 

A 

0 

1      ft 

P    O 

0 

HJ 

o 

«H 

<c  o 

0 

I 

1 

O    (0 

tt)  -H 

CO 

1 

p   * 

* 

T— 

O 

a 

>    D> 

o 

Xi 

| 

o 

<tj 

O    C 

••  c 

a 

r-\ 

1 

p 

T3   -H 

•H    0 

p 

1 

0) 

o> 

C    S 

tt)  -H 

B 

tt)    ^ 

0 

•H     fl 

>    -P 

O 

CO 

s 

u 

>     P 

N    O 

u 

53 

ft 

1     X) 

~    tt) 

O 

tt) 

P 

a 

e 

•H 

3 

P    P 

*    -H 

0 

/ 

tt) 

c 

(0    0 

A   X) 

o 

% 

s 

0) 

tt)     <+-! 

fl  C 

•H 

N 

a 

p 

P   -H 

* 

i 

o  s 

a  i 

a 

I     0 

O  Xi 

£1 

tt> 

z 

P  -0 

O    fl 

fl 

p 

0) 

0  c 

i  -p 

P 

0) 

c 

1     -H 

C    g 

B 

^ 

0 

P  s 

0    0 

O 

01 

0 

o 

o  o 

u 

H 

0)    fl 

•H      1 

1 

O 

iH 

*  p 

p 

P 

Cr 

tt)  p 

0) 

tt) 

n 

CO    o 

P    W 

0) 

•o 

■H 

..    0) 

(d    •• 

•o 

> 

>   -H 

>  -H 

■H 

10 

0 

P    tt) 

<4-l    tt) 

<D 

s 

^  CO 

tt)     > 

s 

> 

r 

X        E 

■O    N 

N 

p 

194  THE  MOVING  ICONS  EXAMPLE  Chapter  10 


10.9  Problem  Set  #9 

Questions 

1.  Make  it  possible  to  individually  erase  icons  that  have  been  drawn  on  the 
main  pane.  (I  think  the  best  way  to  do  so  would  be  to  use  the  mouse  sensi- 
tive items  facility.  You  might  also  try  doing  it  on  your  own,  without  mouse 
sensitive  items.  That  would  probably  entail  duplicating  some  of  the  ms-item 
stuff,  but  the  limited  functionality  required  here  shouldn't  involve  too  much 
duplication.) 

2.  If  you've  chosen  the  mouse  sensitive  item  route  for  (1),  add  some  more  func- 
tions to  the  menu.  For  example,  one  option  might  ask  for  a  keystroke  then 
change  the  icon  to  the  one  corresponding  to  that  character  code  (in  the  same 
font) .  Another  might  prompt  for  the  name  of  a  font  then  redraw  the  icon  in 
that  font  (with  the  same  character  code) . 

3.  In  an  earlier  version  of  the  window-with-comtab  support  code,  the  typeout 
window  didn't  restore  the  image  of  the  window  underneath  it  upon  being 
deexposed.  The  main  pane  therefore  needed  to  be  able  to  regenerate  the  pic- 
ture. Though  it's  no  longer  strictly  necessary  to  have  such  a  : redisplay 
method,  it's  still  a  good  exercise.*  Your  solution  to  (1)  should  give  you  some 
way  of  knowing  what  icons  are  currently  displayed  and  where.  Use  this 
knowledge  to  write  the  :  redisplay  method  —  it  should  do  a  :  clear- 
window  and  then  redraw  the  current  icons.  While  you're  at  it,  make  the 
:  redisplay  method  accessible  through  the  comtab,  via  #\c-L  and 
#\ref  resh. 


Sorry  for  resorting  to  such  a  pedantic  rationale.  I  didn't  plan  it  this  way,  but  at  the  last  minute  I 
ruined  what  had  been  a  perfectly  good  problem  through  my  own  industrious  improvements  to  the 
comtab  code. 


Section  10.9  Problem  Set  #9  195 


Hints 

Don't  forget  to  put  your  code  in  the  "icons"  package! 

1.  Adding  mouse-sensitivity  involves  the  following  steps:  mix  tv:basic-mouse- 
sensitive-items  into  moving-icons-main-pane;  make  an  item  type  alist  with 
tv:add-typeout-item-type,  and  put  it  on  main-pane's  default  plist;  write  the 
function(s)  to  be  called  when  an  item  is  chosen;  and  alter  the  : drop-icon 
method  to  use  the  :  item  or  : primitive-item  messages.  (Processing 
the  blip  and  calling  the  indicated  function  will  be  taken  care  of  by  the 
window-with-comtab  mixin;  your  function  will  be  called  with  one  argument, 
the  item.) 

To  erase  the  icon,  draw  over  it  in  xor  mode.  It's  probably  easiest  to  use  the 
.-draw- char  message.  Since  the  icons  themselves  are  just  character  codes, 
and  don't  contain  information  about  their  screen  position,  you'll  probably 
want  your  mouse-sensitive  items  to  actually  be  some  sort  of  data  structure 
containing  the  x  and  y  coordinates  as  well  as  the  character  itself. 

2.  Erase  the  icon  as  in  (1),  then  redraw  it  with  the  new  character  or  font. 
:  draw- char  is  probably  the  easiest  way  again. 

3.  Assuming  again  that  you've  chosen  the  mouse-sensitive-items  route,  you'll 
need  to  get  at  the  list  of  current  items  in  order  to  redraw  each  of  them.  The 
list  is  the  value  of  the  instance  variable  tv.item-list.  (Remember  to  grab  the 
list  before  doing  the  :  clear-window,  because  the  :  clear-window  will 
set  the  list  to  nil.) 


196  THE  MOVING  ICONS  EXAMPLE  Chapter  10 


Solutions 

1 .  The  structure  representing  the  item  is  a  list  of  the  character  code,  the  current 
font,  and  the  x  and  y  coordinates.  The  advantage  of  including  the  font  is 
that  if  Meta-X  Set  Icon  Font  is  done,  we  can  still  properly  erase  old  icons  in 
the  original  font. 

( def flavor  moving-icons-main-pane 
( ( icon-character  nil ) ) 
(tv:pane-no-mouse-select-mixin 

tv: basic-mouse-sensitive- items  new 

zwei : window-with-comtab ) 
: settable-instance-variables 
( :default-init-plist    :comtab   *icon-comtab* 

: item-type-alist   *icon-item-type-alist* 
: font-map    '( fonts : mouse)  \new 

:blinker-p  nil 
:save-bits   t ) ) 

(defvar   *icon-item-type-alist*   nil) 

(tvradd-typeout- item- type  *icon-item-type-alist*  : icon  "Erase" 

erase-icon  t  "Erase  this  icon.") 

(def method  { moving-icons-main-pane  : drop-icon) 
( mouse -x  mouse-y) 
(if  (not  icon-character)  (beep) 

(multiple-value-bind  (x-off  y-off) 
(send  tv: mouse-blinker  : offsets) 
(send  self  : draw-icon 

(list  icon-character  tv: current-font 

(-  mouse-x  x-off  tv: left-margin-size) 
(-  mouse-y  y-off  tv: top-margin-size) ) 
:add)) 
(setq  icon-character  nil) 
(send  self  : mouse-standard-blinker )) ) 

(defmethod  (moving-icons-main-pane  :draw-icon) 
(char-info  item-action) 
(destructuring-bind  (char  font  x  y)  char-info 
(send  self  : draw-char  font  char  x  y  tv:alu-xor) 
(selectq  item-action 


Section  10.9  Problem  Set  #9  197 


(:add  (send  self  .'primitive-item 
:icon  char-info  x  y 

(+  x  (send  self  : character-width  char  font)) 
(+  y  (font-char-height  font) 
(send  self  :vsp) ) ) ) 
(: delete  (setq  tv:item-list 

(del  #' (lambda  (item  list) 

(eq  item  (second  list))) 
char-info  tv: item-list ) ) ) ) ) ) 

(defun  erase-icon  (char-info) 
(send  zwei : *window-with-comtab* 

: draw-icon  char-info  : delete)) 

( tv : add- typeout- item- type 

♦icon-item-type-alist*  : icon  "Change  Character" 

change-icon-char  nil 

"Replace  this  icon  with  a  different  character.") 

(defun  change-icon-char  (char-info) 
(let  ((new-char  (read-single-char))) 
(process-sleep  30) 

When  the  typeout  window  is  deexposed,  it  restores  the  window 
underneath  to  how  it  was  when  the  typeout  window  was  first 
exposed,  so  if  we  leave  the  typeout  window  exposed  while  we  change 
the  display,  our  changes  will  be  lost  when  it  does  get  deexposed. 
(send  zwei : *typeout-window*    rdeexpose) 
( send   zwei : *window-with-comtab* 

: draw-icon  char-info  : delete) 
(setf  (first  char-info)  new-char) 
(send  zwei : *window-with-comtab* 

:draw-icon  char-info  :add))) 

(defun  read-single-char  nil  this  is  borrowed  from  the  code 

zwei  :  ( LET    ( CHAR )  for  Help-C  (com -self- document) 

(TYPEIN-LINE    "New  char:    ") 
(SETQ   CHAR    (TYPEIN-LINE-ACTIVATE 

(EDITOR-INPUT  :MOUSE  :RETURN) ) ) 
(TYPEIN-LINE-MORE  "~:(5>C"  CHAR) 
char ) ) 

( tv : add- typeout- item- type 

♦icon-item-type-alist*  :icon  "Change  Font"  change-icon-font 


198  THE  MOVING  ICONS  EXAMPLE  Chapter  10 


nil    "Redraw  this   character   in  a  different   font.") 

(defun   change-icon-font    (char-info) 

(let    ( (new- font    (read-font-f rom-mini-buf f er ) ) ) 
(send   zwei : *window-with-comtab* 

: draw-icon   char-info    : delete) 
(setf    (second   char-info)    new-font) 
(send   zwei: *window-with-comtab* 

: draw-icon  char-info    :add) ) ) 

where  ( read-f  ont-f  rom-mini-buf  fer)  is  the  body  of  com -set -icon - 
font  starting  at  ( cdr  .  .  .  ) ,  and  com-set-icon-font  should  be  changed  to 
call  read-font... 

3.    In  addition  to  the  redisplay,   I've  also  thrown  in  a  com-clear-window  to 
remove  all  the  current  icons. 

(defmethod    (moving-icons-main-pane    :redisplay)    nil 
(let    ((old-item-list   tv: item-list ) ) 
(send   self    : clear-window) 
(loop  for    (nil   item)    in  old-item-list 

do    (send   zwei : *window-with-comtab* 
:draw-icon  item    :add)))) 

( zwei : def com  com-redisplay 

"Regenerates   display  from  current  dropped   icons" 
nil 
( send   zwei : *window-with-comtab*    : redisplay) ) 

(zwei: def com  com-clear-window 

"Removes   all   dropped   icons   from  the  window"   nil 
(send   zwei : *window-with-comtab*    : clear-window) ) 

(zwei:set-comtab   *icon-comtab* 

'(#\c-L   com-redisplay 
#\refresh  com-redisplay 
#\clear-input   com-clear-window) ) 


Chapter    11 

MORE  ADVANCED  USE  OF  THE  EDITOR 


The  standard  Zmacs  commands  are  generally  quite  well  documented  by  the  on-line 
help  facilities.  So  there  should  be  no  difficulty  in  becoming  fluent  in  the  use  of  the 
built-in  commands  simply  by  consulting  the  automatic  documentation.  Or,  if  you 
prefer,  many  of  the  more  common  built-in  commands  are  described  on  paper,  in 
Part  I  of  volume  4. 

The  methods  for  adding  new  commands,  on  the  other  hand,  are  not  documented  so 
completely.    It  is  upon  that  topic  that  this  class  will  concentrate. 


11.1  Keyboard  Macros 

keyboard  macros  allow  you  to  bundle  up  any  number  of  keystrokes  and  execute 
them  all  with  one  keystroke.  (These  actually  are  documented,  but  since  they  fit  in 
with  the  rest  of  today's  chapter,  I  thought  we  should  look  at  them  as  well.)  The 
Zmacs  command  "c-X  ("  starts  a  keyboard  macro.  Whatever  keys  you  press 
from  then  up  until  you  type  a  "c-X  )"  are  remembered  while  they  are  executed. 
When  you  type  the  c-X  )  the  macro  will  be  defined.  It  can  be  re-executed  by 
typing    c-X   E.    The  effect  will  be  as  though  you  had  typed  all  the  keystrokes  in 


200  MORE  ADVANCED  USE  OF  THE  EDITOR  Chapter  11 


the  macro  definition  (but  faster).  Giving  a  numeric  argument  to  c-X  E  will  cause 
the  macro  to  be  repeated  that  many  times. 

c-X  E  always  executes  the  most  recently  defined  macro,  so  if  you  define  another 
macro  with  c-X  (,  the  definition  of  the  first  one  will  be  lost,  unless  you  have  pre- 
viously saved  it  somehow.  One  way  of  saving  a  macro  is  to  give  it  a  name,  with 
M-x  Name  Last  Kbd  Macro.  Once  a  macro  has  been  named,  you  can  install  it  on 
a  key  with  M-x  Install  Macro.  The  name  of  the  macro  and  the  keystroke  on  which 
to  install  it  will  be  prompted  for  in  the  mini-buffer.  From  then  on  (until  you  dein- 
stall the  macro,  or  install  some  other  command  on  the  same  key),  typing  that  key- 
stroke will  execute  the  macro.  When  M-x  Install  Macro  asks  for  the  name  of  the 
macro  to  install,  if  you  just  type  a  carriage  return  instead  of  the  name  of  a  macro, 
the  one  most  recently  defined  will  be  installed  on  the  specified  key.  It's  therefore 
unnecessary  to  ever  name  your  macros,  as  long  as  you  install  them  before  defining 
another. 

Here's  a  simple  example,  something  which  I  often  did  while  working  on  the  early 
versions  of  these  lectures,  in  the  troff  text  formatter.  I'll  define  a  keyboard  macro 
for  inserting  the  troff  directives  for  switching  to  an  italic  font  and  back,  and  install 
it  on  super-I. 

c-x  (  start  keyboard  macro  definition 

\f  i\f  p  insert  the  text 

c-B  c-B  c-B  move  the  cursor  back  to  the  correct  position  for  inserting 

italic  text 
c-x   )  end  macro  definition 

M-x  install  Macro      [prompted  with  "Name  of  macro  to  install  (CR  for  last 

macro  defined):"] 
<return>  [prompted  with  "Key  to  get  it:"] 

s-i  [menu  pops  up  for  choosing  which  comtab  to  use] 

<click  on   Zmacs> 

The  next  step,  one  which  I've  been  too  lazy  to  ever  take,  but  really  should,  would 
be  to  put  something  in  my  login  init  file  to  automatically  define  this  keyboard 
macro  every  time  I  login.  As  things  stand,  I  have  to  run  through  the  above 
sequence  of  commands  whenever  I  start  writing  a  text  file  (unless  the  machine 
hasn't  been  booted  since  the  last  time  I  defined  the  macro).  The  way  to  define  a 
keyboard  macro  in  lisp  code  is  with  the  function  zwekdefine-keyboard-macro.  The 
first  argument  is  the  name  the  macro  will  have,  the  second  (usually  nil)  indicates  a 
repeat  count,  and  the  rest  are  the  character  codes  for  the  keystrokes.  Once  the 
macro  has  been  defined,  you  can  insert  it  into  a  comtab.  So  if  I  weren't  so  lazy,  I 
would  add  this  to  my  init  file: 


Section  11.1  Keyboard  Macros  201 


(zwei: DEFINE -KEYBOARD -MACRO  italic-font  (nil) 
#\\  #\f  #\I  #\\  #\f  #\P  #\c-B  #\c-B  #\c-B) 

(zwei : command- store  ( zwei : make-macro-command  : italic-font ) 
#\s-I 
zwei : *zmacs-comtab* ) 

If  I  were  adding  several  macros  at  one  time,  and  to  the  same  comtab,  I  would  use 
set-comtab  rather  than  command-store.  And  as  for  the  choice  of  comtab,  specify- 
ing *zmacs-comtab*  is  equivalent  to  clicking  on  "Zmacs"  in  the  menu  that  M-x 
Install  Macro  pops  up,  and  *standard-comtab*  is  equivalent  to  clicking  on  "Zwei." 
Each  editor  has  its  own  comtab,  but  they  are  all  indirected  to  *zmacs-comtab*,  so 
putting  a  command  there  means  that  it  will  be  accessible  in  all  instances  of  the 
Zmacs  editor,  unless  of  course  the  command  is  shadowed  by  a  binding  to  the  same 
key  in  an  individual  editor's  comtab.  And  *zmacs-comtab*  is  indirected  to 
*standard-comtab*,  as  are  all  the  other  zwei-based  editors*  (e.g.,  Zmail  and  Con- 
verse). So  a  command  inserted  in  *standard-comtab*  will  be  available  in  all  the 
zwei  editors,  unless  shadowed. 


11.2  Writing  New  Commands 

Most  extensions  to  the  editor  are  not  expressible  as  a  sequence  of  keystrokes.  For 
these  you  need  to  write  a  function,  with  defcom,  and  then  add  it  to  the  comtab  of 
your  choice  with  command-store  or  set-comtab.  Among  the  things  you  may  want  to 
do  from  your  function  are:  insert  text  into  a  buffer,  read  text  out  of  a  buffer,  get 
user  input  from  the  mini-buffer,  and  send  text  to  the  typeout  window.  All  of  these 
are  reasonably  straightforward,  once  you  know  about  a  few  key  variables  and  func- 
tions. 


11.3  Buffers  and  Streams 

The  functions  zwekopen-editor-stream  and  zwei:with-editor-stream  open  a  bidirec- 
tional stream  to  an  editor  buffer.  They  are  analogous  to  open  and  with-open-file  in 
that  open-editor-stream  simply  creates  the  stream  and  returns  it,  while  with-editor- 
stream  puts  a  call  to  open-editor-stream  inside  a  useful  wrapper,  and  so  is  prefer- 
able if  your  control  structure  allows  it.    (The  wrapper  in  this  case  guarantees  not  a 


As  I  understand  it,  eine  and  zwei,  apart  from  being  "one"  and  "two"  in  German,  were  the  names  of 
the  first  two  text  editors  written  for  lisp  machines.  They  are  acronyms,  respectively,  for  Eine  Is  Not 
Emacs,  and  Zwei  Was  Eine  Initially. 


202  MORE  ADVANCED  USE  OF  THE  EDITOR  Chapter  11 


close,  which  isn't  meaningful  for  editor  streams,  but  a  :  force-redisplay,  so 
any  changes  to  the  buffer  will  be  apparent.)  Either  of  these  functions  ultimately 
ends  up  calling  interval-stream,  which  does  a  make-instance  of  flavor  interval- 
stream.  For  more  control  over  how  the  stream  is  made,  you  may  wish  to  call 
interval-stream  directly.  But  in  general,  open-editor-stream  provides  a  good 
higher-level  interface. 

There  is  some  documentation  on  these  two  functions  in  chapter  44  of  volume  7, 
mainly  on  the  various  options  for  specifying  which  buffer  the  stream  should  point 
to,  and  where  in  the  buffer  it  should  initially  point.  You  must  specify  at  least  one 
of  the  following  options:  :  interval,  :  buffer-name,  :  pathname,  :  win- 
dow, or  :  start.  :  buffer-name  and  :  pathname  are  easy  enough.  If  a 
buffer  exists  which  matches  the  given  information,  it  is  used;  if  not,  one  is  created 
(unless  the  :create-p  option  has  been  used  to  specify  otherwise).  Understand- 
ing the  others  requires  knowing  a  bit  more  about  the  editor  data  structures. 

The  base  flavor  for  all  buffers  is  zwekinterval.  The  value  of  the  variable 
zwei:*interval*  will  be  the  current  buffer,  an  object  whose  flavor  is  likely  to  be 
something  like  zwehfile-buffer,  which  is  indirectly  built  on  interval  (via  node,  top- 
level-node  and  buffer).  Thus  references  to  the  current  "interval"  mean  the  current 
buffer.  An  interval  may  also  be  created  to  contain  any  portion  of  a  buffer;  some 
intervals  are  actually  buffers,  while  many  others  are  temporary  objects  used  to 
point  to  arbitrary  regions  of  text.  An  object  of  flavor  interval-stream  (see  above)  is 
simply  a  stream  whose  "peripheral  device"  is  an  interval. 

The  interval  flavor  has  (among  others)  two  instance  variables,  for  the  beginning  and 
end  of  the  text  it  refers  to.  These  two  are  represented  as  buffer  pointers,  a  type  of 
object  defined  by  the  zweirbp  defstruct.  A  bp  is  a  list  consisting  of  three  elements: 
an  object  of  type  line  (defined  by  the  zwekline  defstruct),  an  index  into  the  line, 
and  a  keyword  we  needn't  be  concerned  with  here.  A  line,  in  turn,  is  a  string  (the 
text  of  the  line)  with  all  kinds  of  information  in  the  string's  array-leader,  most 
importantly  pointers  to  the  next  and  previous  lines  in  the  buffer.  So  given  an  inter- 
val you  can  get  bp's  for  the  first  and  last  character  positions  in  the  buffer,  given  a 
bp  you  can  tell  what  line  it  refers  to  (as  well  as  which  character  in  the  line),  and 
given  a  line  you  can  find  the  preceding  and  following  lines. 

The  value  of  the  variable  zwei:*window*  is  an  object  of  the  type  defined  by  the 
defstruct  zwei:window  (not  to  be  confused  with  objects  of  type  tvrwindow).  It  con- 
tains information  about  the  portion  of  the  buffer  currently  visible.  Among  its  slots 
are  a  pointer  to  the  interval  (buffer)  that  window  is  displaying  part  of,  a  bp  for  the 
position  of  point  (the  cursor),  a  bp  for  the  first  character  in  the  line  currently 
displayed  at  the  top  of  the  screen,  and  a  count  of  how  many  lines  are  visible.    The 


Section  11.3  Buffers  and  Streams  203 


window  defstruct  uses  the  :  array- leader  type,  meaning  that  the  object  is  an 
array,  with  all  the  slots  going  into  the  array-leader.  The  array  itself  contains  a  row 
of  information  for  each  line  in  the  area  the  window  maps  to,  including  the  "line" 
object. 

The  macro  zwei:point,  called  with  no  arguments,  returns  the  bp  for  the  current 
point.  As  you  might  expect,  the  macro  expands  into  ( ZWEI :  WINDOW-POINT 
ZWEI :  *WINDOW*),  the  accessor  for  the  "point"  slot  of  the  current  window.  A 
similar  macro,  zwei:mark,  returns  a  bp  for  the  most  recently  dropped  mark,  which 
is  another  slot  in  the  window  defstruct. 

Now  back  to  the  options  for  open-editor-stream.  The  ones  we  delayed  discussing 
were  :  interval,  :  window  and  :  start.  We're  now  in  a  position  to  make 
sense  out  of  these.  If  you  use  the  :  interval  option,  the  value  supplied  should  be 
an  interval;  you  may  use  zwei:* interval*  or  any  of  a  number  of  functions  which 
exist  to  create  an  interval  pointing  to  an  arbitrary  text  area.  The  stream  created 
will  read  from  and  write  to  the  given  interval.  The  :  window  option  is  similar;  you 
provide  a  (zwei)  window,  and  open-editor-stream  returns  a  stream  into  that  win- 
dow. The  :  start  option  is  a  little  more  complicated.  It  may  be  used  either 
alone  or  in  combination  with  other  options.  If  the  value  you  provide  is  a  bp,  the 
stream  will  begin  at  the  specified  bp.  In  this  case  no  other  options  need  be  sup- 
plied, and  the  stream's  "end  of  file"  will  be  at  the  end  of  the  buffer  containing  the 
bp.  (You  can  force  some  other  termination  point  with  the  :  end  option.)  The 
other  possible  values  for  :  start  are  all  keywords,  and  all  require  that  some  other 
option  (like  :  interval  or  :  window)  indicate  which  buffer  to  use.  The  effect  of 
the  :  start  keyword  will  be  to  determine  where  within  the  buffer  the  stream  will 
start.  Among  your  choices  are  : beginning,  :end,  :mark,  : point,  and 
:  region. 

There  are  quite  a  few  other  options  to  open-editor-stream  to  control  various  details 
of  its  behavior,  but  the  ones  we've  already  seen  are  sufficient  to  write  all  sorts  of 
useful  applications.  You'll  find  many  examples  in  the  editor  code  to  use  as  models. 
These  are  likely  to  use  interval-stream  directly,  rather  than  through  open-editor- 
stream,  because  open-editor-stream  is  a  relatively  new  feature.  Your  own  functions 
will  probably  be  clearer  and  easier  to  write  if  you  use  open-editor-stream  (or  with- 
edi  tor-stream ) . 

Here  are  a  few  trivial  examples,  to  illustrate  the  basic  concepts.  (All  assume  the 
current  package  is   zwei.) 

(with-editor- stream  (str  : interval  *interval*) 
(send  str  : string-out 


204  MORE  ADVANCED  USE  OF  THE  EDITOR  Chapter  11 


"surprise   text   inserted  at   end  of   current  buffer")) 

(with-edi tor- stream    ( str    : interval   *interval*    : start    : beginning) 
( send   str    : string-out 

"surprise   text   inserted  at  beginning  of   current  buffer")) 

(with-editor-stream    (str    : start    (point)) 

(send   str    : string-out    "surprise   text   inserted  at  point")) 

(with-editor-stream   (str    :buffer-name    "mbox  //usr//hjb//  S:" 
: start    : beginning) 
(send  str    :  line-in))  returns  first  line  of  buffer  containing  my  mbox  file 

One  slightly  subtle  point  to  keep  in  mind  is  that  the  variables  *interval*  and  •win- 
dow* are  not  global;  they're  bound  partway  down  the  stack  in  the  Zmacs  process. 
This  makes  no  difference  if  you're  writing  editor  commands,  because  they'll  be  exe- 
cuted in  the  same  process.  But  it  does  mean  you'll  have  to  be  careful  if  you  write 
code  intended  to  interact  with  the  editor's  buffers  from  another  process,  because 
those  variables  will  then  be  unbound.  In  particular,  of  the  four  examples  just  given, 
the  first  three  would  bomb  if  evaluated  in  a  lisp  listener  (the  third  because  point 
has  to  access  *window*),  while  the  fourth  would  work.  All  four  work  fine  from  the 
editor's  typeout  window  (as  long  as  the  package  is  correct),  since  the  typeout 
window's  break  loop  is  in  the  Zmacs  process. 


11.4  Reading  from  the  Mini-buffer 

Another  set  of  tools  often  used  in  writing  editor  commands  are  the  functions  for 
reading  from  the  mini-buffer.  There  are  many  —  their  names  generally  begin  with 
"typein-line-,"  and  the  varieties  differ  in  how  they  know  when  the  typein  is  com- 
pleted, and  in  what  form  they  return  the  typein.  Here  are  a  few  of  them  (all  in  the 
zwei  package): 

typein-line-readline  ctl-string  &rest  args 

A  prompt  (created  by  format  using  ctl-string  and  args)  is  printed  in  the 
typein  line  (just  above  the  mini-buffer  —  you've  seen  it  used  frequently), 
and  keyboard  input  is  directed  to  the  mini-buffer.  When  the  Return  or  End 
keys  are  pressed,  a  string  is  constructed  out  of  all  the  preceding  characters 
and  returned.   The  behavior  is  analogous  to  that  of  the  readline  function. 

typein-line-read  ctl-string  &rest  args 


Section  11.4  Reading  from  the  Mini-buffer  205 


Same  as  above  except  the  lisp  reader  scans  the  string  before  it  is  returned, 
and  the  lisp  object  returned  by  the  reader  is  returned  from  typein-line-read. 
The  behavior  is  roughly  analogous  to  that  of  the  read  function. 

typein-line-form-to-eval  prompt  &optional  initial -contents  initial -char -pos 

Similar  to  typein-line-readline  except  that  the  Return  key  does  not  terminate 
input  —  it  simply  moves  to  a  new  line.  Only  the  End  key  terminates  input. 
A  string  is  returned  (possibly  containing  Return  characters). 

typein-line-multi-line-read  ctl-string  &rest  args 

Combination  of  typein-line-read  and  typein-line-form-to-eval.  Multiple  lines 
are  read,  terminated  by  End,  and  the  input  is  scanned  by  the  lisp  reader 
before  being  returned. 

read  -buffer-name  prompt  default  &optional  impossible-is-ok-p 

Prints  prompt  in  the  typein  line,  and  does  a  completing  read  in  the  mini- 
buffer,  using  the  names  of  all  the  buffers  as  the  set  of  possible  completions. 
default  is  chosen  if  the  user  just  types  Return.  The  actual  buffer  object 
corresponding  to  the  selected  string  is  returned. 

typein-line-completing-read  history  default  blank-line-defaults  prompt  alist 
&optional  ... 

The  function  called  by  read-buffer-name  (and  many  others)  to  do  the  com- 
pleting read.  It  has  more  options  than  you  even  want  to  think  about  (until 
one  of  them  turns  out  to  be  exactly  the  thing  you  need),  all  of  which  are 
described  in  great  detail  at  the  function  definition.  It  allows  for  the  use  of  a 
history  as  well  as  a  default,  so  you  can  pop  your  way  through  the  history  to 
reuse  earlier  inputs. 

com  pie  ting-read -from -mini -buffer  prompt  *  completing- alist*  &optional  ... 

The  function  called  by  typein-line-completing-read  (and  many  others)  to 
really  do  the  completing  read.  You  may  want  to  call  it  directly  because  it 
has  a  somewhat  simpler  interface,  if  fewer  facilities. 

read-defaulted-pathname  prompt  *  reading-pathname -defaults*  &optional  ... 

Used  by    c-X    c-F  (and  many  others)  to  read  a  pathname  and  merge  it 


206  MORE  ADVANCED  USE  OF  THE  EDITOR  Chapter  11 


with  some  set  of  defaults. 


11.5  A  Real  Example 

Here's  something  taken  out  of  the  editor  code,  the  definition  for  M-x  Evaluate  Into 
Buffer. 

(DEFCOM  COM-EVALUATE-INTO-BUFFER 

"Evaluates  forms  from  the  minibuffer  and  inserts  the 
results  into  the  buffer.   You  enter  Lisp  forms  in  the  minibuffer, 
which  are  evaluated  when  you  press  END.   The  result  of  each 
evaluation  appears  in  the  buffer  before  point.   With  a  numeric 
argument,  it  also  inserts  any  typeout  that  occurs  during  the 
evaluation  into  the  buffer."  (KM) 

(LET  ((FORM-STRING  (TYPEIN-LINE-FORM-TO-EVAL 

"Lisp  forms  to  evaluate:")) 
(OUTPUT- STREAM  ( INTERVAL-STREAM- INTO-BP  (POINT))) 
FORM) 
(WITH-INPUT-FROM-STRING  (INPUT-STREAM  FORM-STRING) 
(LOOP  DO  (CONDITION-CASE  (ERROR) 

(SETQ  FORM  (READ  INPUT-STREAM) ) 

(SYS:END-OF-FILE  (RETURN  DIS-TEXT)) 

(SYS: READ-ERROR  (BARF  ""A"  ERROR))) 

(FORMAT  OUTPUT-STREAM  "-{-&-S-}" 

(LET-IF  *NUMERIC-ARG-P* 

((STANDARD-OUTPUT  OUTPUT- STREAM) ) 
(MULTIPLE-VALUE-LIST  ( EVAL  FORM)))) 
(MOVE-BP  (POINT) 

(FUNCALL  OUTPUT-STREAM  ' :READ-BP) ) ) ) ) ) 

typein-line-form-to-eval  returns  a  string,  presumably  containing  lisp  forms. 
( interval-stream-into-bp  (point))  is  like  (open-editor-stream 
:  start  (point)  :end  (point)).  We  make  input- stream  point  to  the 
string  of  forms,  and  then  loop,  reading  one  form  at  a  time  from  the  string.  For 
each  one,  assuming  there  are  no  errors,  we  use  format  to  print  the  results  of 
evaluating  the  form  into  the  buffer,  via  the  open  editor  stream,  and  move  point. 


Section  11.5  A  Real  Example  207 


.6  Problem  Set  #10 

Questions 

1.  Write  com-comment-out-lines-in-region,  and  com-uncomment-lines-in-region, 
to  insert  (and  remove)  semi-colons  at  the  beginning  of  each  line  in  the  region. 
(Both  of  these  already  exist  as  parts  of  com-comment-out-region,  but  that 
version  includes  lots  of  hair  for  handling  messy  cases.  Write  something  sim- 
ple.) 

2.  Write  com-insert-text-into-other-buffer,  which  should  read  any  amount  of 
text  from  the  mini-buffer  (terminated  by  #\End),  prompt  for  the  name  of  a 
buffer,  and  append  the  text  to  the  end  of  the  given  buffer. 

3.  Write  a  macro  to  be  used  either  inside  or  outside  the  editor,  which  redirects 
all  typeout  during  execution  of  its  body  to  a  newly  created  editor  buffer. 


208  MORE  ADVANCED  USE  OF  THE  EDITOR  Chapter  11 


Solutions 


(This  all  goes  in  the  zwei  package.) 


1.  (defcom  com-comment-out-lines-in-region 

"Comments  out  each  line   in  the  region."   nil 
(region-lines    (start  end) 

(loop  for   line   =   start  then    (line-next   line) 
until    (eq  line  end) 

do    (insert    (create-bp  line   0)    #\;))) 
dis-text) 

( defcom  com-uncomment-lines-in-region 

"Removes   semi-colons   from  beginning  of   each  line   in 
region."   nil 

(region-lines    (start  end) 

(loop  for   line   =   start  then    (line-next   line) 
until    (eq  line   end) 
when    (char-equal    (aref   line   0)    #\;) 

do    (let    ((end-idx    ( string-search-not-char 
#\;    line    1)) 
(start-bp    (create-bp  line   0))) 
(delete-interval 
start-bp 

(if    (null   end-idx)    (end-line   start-bp) 
(forward-char   start-bp  end-idx)))))) 
dis-text) 

Don't  forget  to  add  the  commands  to  a  comtab  so  you  can  use  them.    Do 
something  like: 

(set-comtab  *zmacs-comtab* 

' (#\s-;  com-comment-out-lines-in-region 

#\h-;  com-uncomment-lines-in-region) 
( make-command-alist 

' ( com-comment-out-lines-in-region 
com-uncomment-lines-in-region) ) ) 

2.  (defcom  com-insert-text-into-other-buf fer 

"Appends  text  from  the  mini-buffer  to  the  end  of 
any  buffer."  nil 

(let  ((text  (typein-line-form-to-eval 

"Text  to  append  to  other  buffer:")) 


Section  11.6  Problem  Set  #10  209 


(buffer    (read-buffer-name   "Buffer  to  append  text  to:" 

: other ) ) ) 
(with-editor-stream   ( str    : interval  buffer) 
(send  str    : string-out  text))) 
dis-none) 

3.  Anything  sent  to  standard-output  during  execution  of  body  will  be  inserted 
into  a  buffer  named  buffer-name.  There  will  also  be  messages  inserted 
before  and  after  body  is  executed. 

(def macro  with-output-to-editor-buf fer  ((buffer-name) 

Sibody  body) 
* (with-editor-stream  (standard-output 

: buffer-name  , buffer-name) 
(format  t  "-2X;;;  Diverting  to  buffer  ( ~\datime\) ~2%" ) 
,  @>body 
(format  t  "-2%;;;  End  of  diversion  ( -\datime\) " ) ) ) 

Sample  usage: 

(with-output-to-editor-buf fer  ( "test" ) 

(princ  "The  contents  of  the  FEP  file  system  follows:") 
(print-disk-label) ) 


Chapter    12 

A  QUICK  LOOK  AT  "THE  NETWORK" 


Although  it  is  common  to  refer  to  a  lisp  machine's  connections  to  the  rest  of  the 
world  as  "the  network,"  as  if  the  machine  were  connected  via  a  single  mechanism 
to  a  unified  system  of  linkages,  such  is  not  the  case.  There  are  several  means  of 
communication,  operating  via  several  different  hardware  and  software  protocols. 
And  there  is  considerable  overlap,  with  different  software  protocols  operating  simul- 
taneously over  the  same  hardware.  It's  not  really  very  complicated,  but  it's  easy  to 
become  highly  confused  if  the  basic  issues  are  not  kept  clear. 


12.1  The  "Gee-Whiz"  Overview 

The  first  distinction  to  keep  in  mind  is  between  hardware  and  software.  The 
hardware  basis  for  any  given  network  service  will  be  something  like  coaxial  cable 
and  transceiver  boxes,  or  a  serial  line.  The  software  utilizing  this  hardware,  say 
"Internet"  or  "Chaosnet,"  must  itself  be  viewed  as  composed  of  several  theoreti- 
cally independent  levels.  The  various  pieces  of  this  modularity  are  coordinated  by 
the  namespace  database.  The  terms  used  by  the  namespace  for  the  different  levels 
are  service,  protocol,  and  medium.  (Don't  be  concerned  if  the  exact  meaning  of  the 
various  concepts  is  not  clear  at  this  point;  all  that  matters  for  now  is  that  you  have 


212  A  QUICK  LOOK  A  T  "THE  NETWORK"  Chapter  1 2 


a  general  understanding  of  what  sorts  of  entities  the  terms  refer  to.)  The  distinc- 
tions may  at  times  appear  somewhat  strained  or  artificial,  but  in  general  a  service  is 
the  highest  level  entity,  describing  what  the  user  wants  out  of  the  network  connec- 
tion. A  service  may  be  discussed  without  reference  to  which  network  is  providing 
it.  Typical  services  are  file  transfer  and  remote  login.  Each  network  has  its  own 
protocol  (s)  for  providing  any  particular  service.  Chaosnet  provides  file  transfer  ser- 
vice via  the  "qfile"  protocol,  while  Internet  provides  the  same  service  via  the  "tftp" 
protocol.  A  medium  is  a  mode  of  connection,  like  "byte-stream"  or  "chaos";  each 
protocol  requires  some  medium  as  the  minimal  type  of  connection  which  must  be 
present  for  the  protocol  to  operate.  A  connection  can  be  made  to  a  remote  host  in 
order  to  request  a  certain  service  when  both  the  local  and  remote  hosts  are  on  a 
network  of  a  type  adequate  to  support  the  medium  required  by  the  protocol  under 
which  the  remote  host  offers  the  desired  service. 

Let's  look  at  excerpts  from  the  namespace  descriptions  of  two  machines  to  see  some 
of  this  terminology  in  action. 

HOST  JONES 

SYSTEM-TYPE  UNIX 

MACHINE-TYPE  VAX 

ADDRESS  CHAOS  1015 

ADDRESS  INTERNET  192.11.39.9 

ADDRESS  TAMDHU- SERIAL  3 

SERVICE  FILE  CHAOS  QFILE 

SERVICE  LOGIN  SERIAL- PSEUDONET  TTY-LOGIN 

SERVICE  LOGIN  TCP  TELNET 

This  (partly  fictional)  fragment  states  that  the  UNIX  host  "jones"  has  addresses  on 
the  chaos,  internet  and  tamdhu-serial  networks,  and  that  it  offers  the  file  service 
(file  transfers)  via  the  qfile  protocol  on  the  chaos  medium,  and  the  login  service 
(remote  login)  via  either  the  tty-login  protocol  on  the  serial-pseudonet  medium,  or 
the  telnet  protocol  on  the  tcp  medium. 

HOST  TAMDHU 
SYSTEM-TYPE  LISPM 
MACHINE-TYPE  LISPM 
ADDRESS  CHAOS  1003 
ADDRESS  TAMDHU-SERIAL  0 
ADDRESS  INTERNET  192.11.39.5 

And  this  fragment  tells  us  that  the  lisp  machine  "tamdhu"  is  on  the  chaos, 
tamdhu-serial  and  internet  networks.    Combining  this  with  the  description  of  jones, 


Section  12.1  The  "Gee -Whiz"  Overview  213 


we  can  tell  that  from  tamdhu  a  user  could  invoke  file  transfer  service  on  jones, 
since  both  machines  are  on  the  chaos  network  (and  chaosnet  supports  the  chaos 
medium) .  As  for  remote  login  service,  the  user  gets  a  choice:  s/he  could  invoke  it 
on  the  network  called  "tamdhu-serial"  (which  both  hosts  are  on,  and  which  sup- 
ports the  serial-pseudonet  medium)  or  on  Internet  (which  supports  the  tcp 
medium) . 


12.2  The  Beginning  of  the  Real  Explanation 

Until  recently,  what  most  people  had  in  mind  when  they  said  "the  network"  with 
reference  to  lisp  machines  was  Chaosnet,  a  local  area  network  developed  in  1975  by 
the  MIT  AI  Lab,  specifically  for  use  as  the  medium  for  communications  among  lisp 
machines.  But  as  it  was  designed  to  minimize  the  difficulty  of  bringing  other  kinds 
of  machines  into  the  network,  by  now  quite  a  variety  of  computers  —  as  well  as 
peripherals  —  may  be  connected  via  Chaosnet.  The  "chaos"  in  the  name  refers  to 
the  lack  of  centralized  control. 

The  hardware  and  software  portions  of  Chaosnet,  although  designed  for  each  other, 
are  logically  independent.  The  Chaosnet  software  may  operate  on  media  other  than 
the  Chaosnet  hardware,  and  the  software  for  other  network  protocols  may  use  the 
Chaosnet  hardware.  The  transmission  medium  is  sometimes  called  ethernet,  which 
can  be  misleading  because  the  same  term  is  applied  to  a  type  of  network  (including 
hardware  and  software)  developed  by  Xerox.  But  since  the  Ethernet  hardware  and 
the  Chaosnet  hardware  are  largely  compatible,  the  term  "Ethernet"  is  frequently 
applied  to  the  hardware  for  any  network  using  this  sort  of  transmission  medium, 
regardless  of  which  software  protocol  is  in  operation. 

We'll  return  to  Chaosnet  shortly,  but  first  let's  complete  the  overview  of  the  lisp 
machine's  network  connections.  Coexisting  with  Chaosnet  on  the  ethernet  cable  is 
the  Internet,  an  entirely  different  software  protocol.  The  hardware  requirements  of 
the  two  types  of  network  are  compatible;  although  some  kinds  of  computers  use 
different  boards  for  the  two  interfaces,  everything  external  to  the  individual 
machines  is  identical.  In  the  case  of  the  lisp  machine,  even  the  internal  hardware  is 
shared,  so  the  distinction  between  the  two  networks  is  solely  what  happens  to  the 
transmitted  information  in  software.  The  software  for  Internet  is  not,  however,  part 
of  the  basic  lisp  machine  system.  It's  another  product  which  must  be  purchased 
separately,  as  "ip-tcp."  The  Bell  Labs/Murray  Hill  lisp  machine  community  has  a 
site  license,  and  ip-tcp  is  installed  on  all  our  machines.  As  with  Chaosnet,  Internet 
is  understood  by  a  wide  variety  of  computers.  In  fact,  Internet  has  become  a 
Department  of  Defense  standard,  so  one  may  reasonably  expect  virtually  all 
manufacturers  to  support  Internet  in  their  new  products,  while  Chaosnet  may  be 


214  A  QUICK  LOOK  AT  "THE  NETWORK"  Chapter  12 


expected  to  gradually  fade  from  view. 

The  third  means  of  communication  available  to  the  lisp  machine  is  the  serial  i/o 
facility.  Each  lisp  machine  has  three  serial  ports,  which  may  be  used  to  communi- 
cate with  any  device  that  understands  the  RS-232  protocol.  At  my  site  we  connect 
these  ports  to  a  VAX*  terminal  line,  to  allow  use  of  the  lisp  machine  as  a  terminal 
logged  in  to  a  UNIX  system,  or  to  speech  synthesizer  boxes,  or  a  modem.  Because 
the  related  software  uses  a  construct  called  a  serial-pseudonet,  it  appears  from  the 
user's  point  of  view  that  each  lisp  machine  is  the  center  of  its  own  star-shaped  net- 
work (on  an  equal  footing  with  Chaosnet  and  Internet)  connecting  it  to  the  devices 
at  the  other  end  of  the  serial  lines. 

So  all  together  there  are  two  kinds  of  physical  connection  to  the  outside  world  (eth- 
ernet  and  serial  line),  and  three  kinds  of  conceptual  connection  (Chaosnet  and 
Internet  via  the  single  ethernet,  and  serial-pseudonet  via  any  number  of  serial 
lines).  The  term  "network"  —  now  that  Chaosnet  no  longer  stands  alone  —  usu- 
ally refers  to  these  three  conceptual  connections,  either  one  of  them  taken  individu- 
ally or  the  set  of  them  considered  collectively.  It  is  possible,  though  unusual,  to 
define  additional  types  of  conceptual  networks,  sharing  the  existing  physical  connec- 
tions. 

Most  of  the  physical  and  conceptual  connections  are  documented  in  volume  9  of  the 
Symbolics  manuals,  from  which  I  have  borrowed  for  this  chapter.  Chaosnet,  both 
hardware  ("ethernet")  and  low-level  software,  is  covered  in  chapter  15.  Part  I  of 
volume  9  describes  the  namespace  database  and  how  the  namespace  manages 
requests  for  network  services.   Serial  i/o  is  in  Part  III  of  volume  5. 


12.3  The  Ethernet 

The  transmission  medium  (the  ether)  which  supports  both  Chaosnet  and  Internet  is 
1/2  inch  coaxial  cable,  with  a  transceiver  box  at  each  point  where  a  machine  joins 
the  cable.  A  single  ether  must  be  a  linear  cable,  with  no  branches  or  loops.  The 
maximum  length  of  an  ether  is  about  a  kilometer.  Multiple  ethers  may  be  joined 
by  bridges,  i.e.,  machines  on  both  of  two  ethers,  which  relay  packets  from  one  to 
the  other,  so  that  the  two  subnets  may  act  as  one  large  ethernet  without  exceeding 
the  length  limitation.  For  example,  the  portion  of  the  Murray  Hill  ethernet  that 
local  lisp  machine  users  need  to  be  concerned  with  has  three  single  ethers  joined  by 
bridges.  One  connects  all  the  building  2  lisp  machines  (except  Churchill),  about 
five  VAXen  and  some  Sun  workstations;  one  (the  "tempo  net")  connects  a  variety 


VAX  is  a  trademark  of  Digital  Equipment  Corporation. 


Section  12.3  The  Ethernet  215 


of  machines  in  building  3;  the  third  (the  "backbone")  runs  for  about  a  mile  (with 
repeaters  inserted  at  strategic  points,  since  a  mile  is  more  than  a  kilometer)  con- 
necting the  other  two  subnets  and  who  knows  what  else,  hitting  about  fifty 
machines  along  the  way.  Sola  (a  VAX  in  building  2)  serves  as  the  bridge  between 
the  building  2  subnet  and  the  backbone;  Vivace  links  the  backbone  and  the  tempo 
net.  The  current  list  of  subnets  can  be  found  in  /etc/networks  on  any  UNIX 
machine  running  Internet. 

Returning  to  the  operation  of  a  single  ether,  one  machine  at  a  time  may  seize  the 
ether  and  transmit  a  packet  with  the  address  of  some  other  machine.  The  packet 
will  be  seen  by  every  machine  connected  to  the  ether;  it  is  up  to  each  to  check  the 
address  in  the  packet  and  decide  (in  hardware)  whether  it  is  the  intended  recipient. 
If  the  address  is  correct,  the  packet  is  received  and  relayed  up  to  the  appropriate 
software  (Chaosnet  or  Internet,  depending  on  the  type  of  the  packet).  Otherwise  it 
is  ignored. 

The  ether  can  tolerate  temporary  breaks  in  the  cable  for  about  a  minute  —  long 
enough  to  splice  a  transceiver  in  or  out  of  the  ether.  The  effects  of  longer  breaks 
vary  with  the  type  of  the  machine,  but  can  be  disastrous  for  some  —  VAXen  crash 
when  reconnected  after  a  long  break.  If  such  a  machine  is  to  be  spliced  out  of  the 
network  while  running,  a  pair  of  terminators  should  be  attached  to  its  transceiver. 
The  terminators  present  an  impedance  similar  to  that  of  an  intact  ether,  so  the 
machine  sees  what  appears  to  be  a  legitimate  ether  which  just  happens  to  be  com- 
pletely inactive.   It  can  later  be  reattached  with  no  difficulty. 

Lisp  machines  are  insensitive  to  ether  disruptions.  To  physically  remove  a  lispm 
from  the  network  it  is  safe  and  easy  to  disconnect  the  transceiver  cable  where  it 
plugs  into  the  back  of  the  machine.  You  may  reconnect  at  any  time.  Actually,  it's 
rarely  necessary  to  physically  disconnect  the  machine.  The  equivalent  may  be  done 
in  software  by  evaluating  (neti :  reset ),  which  disables  the  ethernet  interface, 
(neti:  enable)  starts  it  up  again.  The  CP  command  Reset  Network  does  a 
reset  immediately  followed  by  an  enable. 


12.4  Chaosnet 

The  previous  section  discussed  the  portion  of  Chaosnet  which  is  shared  with  Inter- 
net, i.e.,  the  Ethernet  hardware.  Now  a  bit  about  the  portions  which  are  unique  to 
Chaosnet. 

Chaosnet  addresses  are  simple  numbers,  consisting  of  three  or  more  octal  digits. 
The  least  significant  eight  bits  indicate  the  machine's  address  on  its  own  subnet,  or 


216  A  QUICK  LOOK  AT  "THE  NETWORK"  Chapter  12 


single  length  of  ethernet  cable.  The  higher  order  bits  indicate  which  subnet  the 
machine  is  on.  The  subnet  codes  used  in  Murray  Hill  are  1  for  the  backbone,  2  for 
building  2,  and  3  for  the  tempo  net.  So  an  octal  address  of  406  (Pancake's 
address)  means  machine  06  on  the  backbone.  Note  that  the  numbering  of 
machines  on  a  subnet  has  no  relation  to  their  physical  order.  A  lisp  machine's 
opinion  of  what  its  own  address  is  comes  from  the  "Set  Chaos-address"  fep  com- 
mand. Every  boot  file  should  have  one  of  these.  The  machine's  opinion  as  to  its 
name  is  derived  from  its  address:  it  believes  whatever  the  namespace  database  says 
is  the  mapping  between  names  and  addresses.  So  all  that's  required  to  make 
Abelour  (address  1002)  believe  that  it's  really  Glengarioch  (address  1006)  is  to 
boot  Abelour  from  a  boot  file  that  contains  the  line  "Set  Chaos-address  1006."  No 
physical  alterations  to  the  network  connections  are  involved.  Then  Abelour  will 
receive  and  answer  any  packets  intended  for  Glengarioch.  There  is  no  sense  in 
which  Abelour  will  not,  in  fact,  be  Glengarioch.  (To  avoid  having  two  Glen- 
gariochs,  this  stunt  should  only  be  pulled  when  Glengarioch  is  down,  or  itself 
booted  as  somebody  else.)  The  file  "fep0:>  namespace. boot"  on  Abelour  does 
exactly  this.  We  boot  Abelour  as  Glengarioch  if  the  real  Glengarioch  (our 
namespace  server)  is  down,  so  that  Abelour  will  act  as  the  namespace  server  until 
Glengarioch  is  fixed. 

The  same  method  for  address-swapping  allows  us  to  transform  Laphroaig  (1001) 
into  Ghost-of-Laphroaig  (401),  but  since  the  new  address  implies  being  on  a 
different  subnet,  the  switch  additionally  involves  plugging  the  machine  into  a  nor- 
mally unused  transceiver  on  the  backbone.  This  trick  allows  us  to  transfer  large 
files  (like  world  loads)  to  machines  on  the  backbone  without  having  to  go  through 
the  bridge.  Executing  a  band  transfer  through  a  bridge  takes  at  least  twice  as  long 
as  going  direct,  as  well  as  completely  tying  up  the  chaos  server  on  the  bridge  for 
the  duration. 

A  UNIX  machine's  idea  of  who  is  at  what  address  is  based  on  the  contents  of  its 
host  table.  The  Chaosnet  host  table  is  in  the  file 
/usr/chaos/lib/libhosts/hosts. local.    (The  Internet  host  table  is  in  /etc/hosts.) 

From  volume  9,  15.3:  "The  principal  service  provided  by  Chaosnet  is  a  connection 
between  two  user  processes.  This  is  a  full-duplex  reliable  packet-transmission  chan- 
nel. The  network  undertakes  never  to  garble,  lose,  duplicate,  or  resequence  the 
packets...  When  first  establishing  a  connection,  it  is  necessary  for  the  two  commun- 
icating processes  to  contact  each  other...  One  process  is  designated  the  user,  and  the 
other  is  designated  the  server.  The  server  has  some  contact  name  [indicating  the 
type  of  service]  to  which  it  listens.  The  user  process  requests  its  local  operating 
system  to  connect  it  to  the  server,  specifying  the  network  address  and  contact  name 
of  the   server.     The   local   operating   system   sends   a   message    (a   Request  for 


Section  12.4  Chaosnet  217 


Connection,  or  RFC)  to  the  remote  operating  system,  which  examines  the  contact 
name  and  creates  a  connection  to  an  existing  listening  process,  or  creates  a  new 
server  process  and  connects  to  it,  or  rejects  the  request." 

The  first  option  (an  existing  process)  is  used  for  simple  requests  that  can  be 
answered  quickly  and  easily,  such  as  a  request  for  the  current  time.  The  main 
server  process  handles  these  itself.  More  elaborate  requests,  which  require 
extended  attention  and  multiple  interchange  of  packets,  are  handled  by  spawning  a 
new  process  for  that  purpose.  On  a  UNIX  chaos  server,  this  means  simply  execut- 
ing a  file  in  the  /usr/chaos/server  directory.  The  name  of  the  file  will  be  exactly 
the  contact  name  that  was  used  to  request  the  connection.  So,  for  example,  if  a  lisp 
machine  wants  to  read  a  file  from  a  UNIX  machine,  it  would  send  an  RFC  packet 
to  the  UNIX  machine,  with  contact  name  "FILE."  The  chaos  server  on  the  UNIX 
end,  upon  receiving  the  packet,  would  start  up  a  process  running  the  contents  of  the 
file  /usr/chaos/server/FILE.  The  chaos  server  would  then  route  any  further  pack- 
ets related  to  the  file  transfer  to  this  new  process.  The  effect  is  as  though  the  FILE 
process  on  the  UNIX  system  and  the  process  requesting  the  file  transfer  on  the  lisp 
machine  were  communicating  directly  with  each  other. 

From  a  lisp  machine,  the  easiest  way  to  establish  a  connection  with  a  server  process 
on  a  remote  host  is  with  the  function  chaos:open-stream.  The  two  required  argu- 
ments specify  the  host  and  the  contact  name.  (Several  optional  keyword  arguments 
offer  more  detailed  control  of  the  type  of  connection.)  If  a  connection  is  success- 
fully established,  chaos:open-stream  returns  an  open  stream  object.  You  may  then 
use  all  the  usual  messages  to  read  characters  from  and  write  characters  to  the 
stream.  Conversion  to  and  from  the  packet  level  is  completely  transparent  —  all 
the  user  sees  is  a  character  stream. 


12.5  A  Bit  More  on  Serial  Streams 

The  programmer  interface  to  the  serial  i/o  facility  also  works  via  lisp  stream 
objects.  The  function  si:make-serial-stream  returns  an  open  stream  to  one  of  the 
serial  ports  (which  one  may  be  specified  with  the  :unit  keyword  argument).  The 
usual  messages  for  reading  and  writing  may  again  be  used.  Details  are  in  chapters 
21  and  22  of  volume  5. 


12.6  The  Role  of  the  Namespace 

The  namespace  database  coordinates  interaction  with  the  various  network  facilities. 
It  is  always  possible  to  directly  manipulate  the  stream  connections  as  outlined 


218  A  QUICK  LOOK  AT  "THE  NETWORK"  Chapter  12 


above,  but  this  is  necessary  only  if  you  are  adding  a  new  type  of  network  service. 
To  invoke  any  existing  service  which  has  already  been  integrated  into  the 
namespace,  you  may  use  the  higher-level  interface  provided  by  the  namespace. 
This  interface  insulates  the  user  from  having  to  know  any  details  about  how  the 
connection  is  established,  or  even  which  network  is  used.  The  namespace  takes  care 
of  finding  an  appropriate  path. 

The  simplest  way  to  invoke  a  network  service  through  the  namespace  is  with  the 
function  net:invoke-service-on-host.  The  first  argument  is  the  name  of  a  defined  ser- 
vice, and  the  second  is  a  host  object.  The  local  host  will  find  the  best  path  to  the 
target  host,  over  all  available  network  connections,  and  use  it  to  invoke  the  named 
service.  So  to  obtain  Sola's  idea  of  what  time  it  is,  I  could  do  (net:  invoke- 
service-on-host  :time  ( si : parse-host  's)).  (Seeing  as  how  Sola's 
namespace  entry  says  that  it  provides  the  time  service  via  the  time-simple 
protocol  on  the  chaos-simple  medium,  we  can  tell  this  will  end  up  being  a 
Chaosnet  transaction,  but  we  needn't  be  concerned  with  that  level  of  detail.) 

In  cases  where  you  need  some  service  but  don't  care  on  which  host  it  is  invoked,  the 
function  net:hnd-paths-to-service  (called  with  an  argument  of  the  service  name) 
returns  a  list  of  service  access  paths,  one  for  each  host  which  provides  the  service. 
The  list  is  sorted  by  decreasing  desirability.  Having  decided  which  path  to  use,  you 
may  invoke  the  service  by  calling  net:invoke-service-access-path  on  the  chosen  ser- 
vice access  path. 

Another  option  is  to  invoke  a  service  simultaneously  on  more  than  one  host,  with 
service  futures.  You  can  then  pick  the  first  or  best  of  several  responses  without  a 
long  waiting  period.  The  handiest  way  to  manipulate  service  futures  is  with  the 
macro  net:invoke-multipIe-services.  This  example  prints  every  host's  idea  of  the 
current  time,  ignoring  those  which  fail  to  respond: 

(defun  all-hosts-time  () 

( net : invoke-multiple-services 

( (net :f ind-paths-to- service  :time)  (*  60  10)  "Time") 
(host  time) 

(sys : network-error  nil)        ;  catch  the  error  and  do  nothing 
( : no-error 
(format  t  "~&~A:  ~ : [unknown- ; ~\TIME\- ] "  host  time  time)))) 


Section  12.6  The  Role  of  the  Namespace  219 


12.7  Troubleshooting 

Typing  Function-H  [or  evaluating  (hostat)]  will  show  which  machines  your 
lispm  is  able  to  contact  via  Chaosnet.  If  you  can't  reach  any  remote  hosts,  some- 
thing is  probably  wrong  locally.  If  you  can  reach  some  and  not  others,  something  is 
probably  wrong  out  in  the  network  somewhere.    Here  are  a  couple  of  hints: 

Don't  forget  about  netirreset  and  neti:enable.  If  a  reset  has  been  done,  hostat  will 
fail  everywhere. 

The  transceiver  cable  locks  into  place,  at  both  the  machine  and  transceiver  ends, 
with  a  tab  which  is  slid  sideways  after  the  connector  is  pushed  into  the  socket.  A 
fairly  common  cause  of  "network  failure"  is  for  the  cable  to  fall  off  the  back  of  the 
machine  because  the  tab  wasn't  used  (or  was  defective). 

Check  the  state  of  the  process  called  "3600  Ethernet  Receiver"  in  Peek.  If  it's  not 
"Ethernet  Packet,"  something's  wrong  —  maybe  you  ignored  a  Function-0-S 
notification. 

For  more  elaborate  troubleshooting,  try  the  "network"  option  in  Peek. 


APPENDIX:     BASIC  ZMACS  COMMANDS 


While  it  is  true  that  there  are  a  great  many  Zmacs  commands,  and  trying  to  learn 
them  all  would  be  a  close  to  hopeless  task,  it  is  also  true  that  the  situation  is  really 
much  less  difficult  than  it  might  at  first  appear.  For  one  thing,  you  can  edit  files 
quite  effectively  with  a  relatively  small  subset  of  the  Zmacs  commands.  (This 
should  not  be  taken  to  imply  that  the  remaining  commands  are  superfluous;  the 
"quite  effective"  editing  you  can  do  without  them  is  transformed  into  astonishingly 
effective  editing  with  them.)  Another  saving  grace  is  that  there  is  some  pattern  to 
the  pairing  of  keystrokes  with  editing  functions.  For  instance,  control  characters 
often  act  on  single  letters  or  lines;  meta  characters  on  words,  sentences,  or  para- 
graphs; and  control-meta  characters  on  lisp  expressions.  Thus  c-F  moves  forward 
one  character,  m-F  moves  forward  one  word,  and  c-m-F  moves  forward  one  lisp 
expression.  c-K  means  "kill"  (delete)  to  the  end  of  the  line,  m-K  means  kill  to  the 
end  of  the  sentence,  and  c-m-K  means  kill  to  the  end  of  the  current  lisp  expression. 
So  the  amount  of  memorizing  you  have  to  do  to  start  editing  is  really  not  very 
great. 

I  can't  overemphasize  the  utility  of  the  Help  facility  in  Zmacs.  It  can  be  a  real 
lifesaver,  both  when  you  don't  know  what  commands  there  are  to  do  something, 
and  when  you've  forgotten  how  to  invoke  a  command  you  know  about.  So  don't 
limit  yourself  to  the  commands  listed  below.   Consider  the  list  a  crutch,  to  help  get 


222 


APPENDIX:   BASIC  ZMACS  COMMANDS 


you  started,  but  try  to  leave  it  behind  as  soon  as  possible. 


Movement  Commands 


C-F 
c-B 
C-N 
c-P 
C-A 
C-E 
mous 


e   left 


Move  forward  one  character 
Move  backward  one  character 
Move  down  one  line  ("next") 
Move  up  one  line  ("previous") 
Move  to  the  beginning  of  the  line 
Move  to  the  end  of  the  line 
Move  to  mouse  position 


m-F 
m-B 
m-A 
m-E 
m-[ 
m-] 
m-< 
m-> 


Move  forward  one  word 

Move  backward  one  word 

Move  to  the  beginning  of  the  sentence 

Move  to  the  end  of  the  sentence 

Move  to  the  beginning  of  the  paragraph 

Move  to  the  end  of  the  paragraph 

Move  to  the  beginning  of  the  buffer 

Move  to  the  end  of  the  buffer 


c-m-F 
c-m-B 
c-m-A,  c- 
c-m-E,  c- 


m-[ 
m-] 


Move  forward  one  lisp  expression 

Move  backward  one  lisp  expression 

Move  to  the  beginning  of  the  current  definition 

Move  to  the  end  of  the  current  definition 


Deletion  Commands 

c-D  Delete  forward  one  character 

Rubout  Delete  backward  one  character 

Clear   Input  Delete  to  the  beginning  of  the  line 

c-K  Delete  to  the  end  of  the  line 

m-D  Delete  forward  one  word 

m-Rubout  Delete  backward  one  word 

m-K  Delete  forward  one  sentence 


c-m-K 
c-m-Rubout 


Delete  forward  one  lisp  expression 
Delete  backward  one  lisp  expression 


APPENDIX:   BASIC  ZMACS  COMMANDS 


223 


C-Y 
m-Y 


Restore  ("yank")  text  deleted  with  any  of  the  above,  except  c-D 
and  Rubout 

Immediately  following  a  c-Y  or  another  m-Y,  replace  the  yanked 
text  with  the  previous  element  of  the  kill  history 


c-Space 


c-W 
m-W 
mouse  middle 

mouse  drag  left 


Region  Commands 

Set  the  mark  at  the  current  position,  and  turn  on  the 

"region."   Subsequent  movement  commands  will  define  the 

region  to  be  the  area  between  the  mark  and  the  new 

position. 

Delete  the  region,  putting  it  on  the  kill  history 

Put  the  region  on  the  kill  history  without  deleting  it 

Mark  (make  into  the  region)  the  object  the  mouse  is 

pointing  at 

Mark  the  area  dragged  over  (between  button  press  and 

button  release) 


File  Commands 


C-X    C-F 


c- 

-X 

c-S 

c 

-X 

c-W 

M 

-x 

Compi 

le 

File 


Read  ("find")  a  file  into  its  own  buffer,  creating  an 
empty  buffer  if  the  file  doesn't  exist 
Write  ("save")  a  buffer  back  to  its  file 
Write  a  buffer  to  any  file,  specified  by  name 
Compile  a  file,  i.e.,  write  a  binary  version  of  the  file. 
This  has  no  effect  on  the  current  Lisp  environment. 
(Compare  to  M-x  Compile  Buffer.) 


Buffer  Commands 

c-m-L  Switch  to  the  previous  ("last")  buffer 

c-X  B  Switch  to  a  buffer  specified  by  name 

c-X  c-B      Display  a  list  of  the  buffers 


c-sh-E 


Lisp  Commands 

Evaluate  (call  the  Lisp  interpreter  on)  the  region,  if 


224 


APPENDIX:   BASIC  ZMACS  COMMANDS 


c-sh-C 

M-x  Evaluate  Buffer 
M-x  Compile  Buffer 


End,  s-E 


it's  active,  or  the  current  definition  if  it's  not 

Compile  the  region  or  current  definition  into  the  Lisp 

environment 

Evaluate  the  entire  buffer 

Compile  the  entire  buffer  into  the  environment.   This 

has  no  effect  on  the  file  system.    (Compare  to  M-x 

Compile   File.) 

Murray  Hill  Standard  Utilities  only.   Evaluate  the 

region  or  current  definition  and  insert  the  result  into 

the  buffer. 


Miscellaneous 


Suspend  Enter  the  typeout  window.    (Resume  returns.) 

m-  .  Find  the  definition  of  a  given  function 

c-X  D  Directory  edit  —  shows  a  directory  listing  and  enables  manipulation 

of  the  files  in  it 

Help  A  Apropos  —  list  all  commands  containing  a  given  substring 

Help  C  Describe  the  command  associated  with  a  given  keystroke 

Help  D  Describe  a  command  specified  by  name 


INDEX 


*  variable   52-53 

*catch  special  form    64 

*throw  function    64 

:  activate  method   48 

: alias-f or-selected-windows 

method   87 
:blinker-p  init  keyword   88 
:  bury  method    49 
: byte-size  open  option    126 
:  canonical-type  method    133 
:case  method  combination    180 
:  character  blinker    186 
:  characters  stream  operation    121 
:  checker  defresource  option    163 
:  choose  method    142-143 
:  clear- input  stream  operation    122 


:  clear-output  stream  operation 

122 
:  clear-screen  stream  operation 

123 
: clear-window 

method   76,  195 

stream  operation    123 
:  close  stream  operation    122 
:  compile  make-system  option    167 
:compile-load  defsystem  clause 

166 
:  component- systems  defsystem 

clause    167 
: compute-all-handlers-once 

method   40 
rconfigurat ions  init  keyword   87 


226 


INDEX 


:  constructor  defresource  option 

162 
:  creation-date  stream  operation 

128 
:  deactivate  method   48 
rdeexpose  method   48-49 
:  default-font  init  keyword    185 
:default-init-plist  defflavor 

option   87-88 
:  describe  method   31 
:  deselect  method   48 
rdevice  method    133 
: direction 

open  option    125 

stream  operation    121 
:  directory  method    133 
:  do- components  defsystem  clause 

167 
:  draw- char  method    195 
:  draw-circle  method   76 
: draw- line  method   36 
:  draw-lines  method   36 
:  draw-point  method   76 
:  draw-rectangle  method   76 
:  draw- triangle  method   76 
:  execute  method    141-143 
:  expose  method   48 
:  fas  load  defsystem  clause    166 
:  finder  defresource  option    163 
:  finish  stream  operation    122 
:  force -output  stream  operation 

122 
:  force-redisplay  method   202 
:  free-list-size  defresource 

option    164 
:  get  method    133 
:get-handler-f  or  method   31 
: gettable-instance-variables 

defflavor  option    19 


;  host  method    133 

;  if -exists  open  option    126 

;  included-f lavors  defflavor 

option   23 
:  init  method   84 
; initable-instance-variables 

defflavor  option   20 
;  initial-copies  defresource 

option    163 
;  initializer  defresource  option 

162 
;  inside-size  method   76 
litem  method   90,  195 
:  item-list  init  keyword    185 
ikill  method   48 
:  length  stream  operation    128 
:  listen  stream  operation    121 
:  matcher  defresource  option    163 
:menu  blip    141-143 
: method-combination  defflavor 

option   28 
:  module  defsystem  clause    166 
:  mouse  -buttons  method    142 
: mouse-click, 

essential-mouse's  method  for   30 

method   29,  86,  89-90,  143 
:  mouse-moves  method   90 
: mouse-standard-blinker 

method  186-187 
:name  method  133 
: new-canonical -type  method 

133 
:  new-device  method    133 
:  new-directory  method    133 
:  new-name  method    133 
:  new-pathname  method    133 
:  new-raw-device  method    133 
: new-raw-directory  method    133 
:  new-raw-name  method    133 


INDEX 


227 


:  new-raw-type  method    133 

:  new- type  method    133 

:  new- vers  ion  method    133 

:  no- error  condition-case  clause    177 

rnoconf  irm  make-system  option 

168 
:  or  method  combination   29,  89 
:  override  method  combination   89 
:  package  defsystem  clause    167 
:  panes  init  keyword   87 
:  patchable  defsystem  clause    167 
:  pathname  stream  operation    128 
: pathname-default  defsystem 

clause    166 
:plist  method    133 
: primitive-item  method   90,195 
:  print -only  make-system  option 

168 
:  print- self  method   31,140 
:  proceed  method    178,180 
:proceed-type-p  method    180 
:proceed-types  method    180 
: process  init  keyword   88 
:  properties  method    133 
:  putprop  method    133 
:  raw-device  method    133 
: raw-directory  method    133 
:  raw-name  method    133 
:  raw- type  method    133 
:read-cursorpos  stream  operation 

122 
:  read-pointer  stream  operation 

123 
:  remprop  method    133 
:  report  method    175 
: required-init-keywords 

deffiavor  option   84 
:reverse-video-p  method   76 
:rows  init  keyword    185 


select  method   48,  87 
selectable-windows  method   87 
selected-pane  init  keyword   87 
send-if-handles  method   84 
set-character  method    186 
set-cursorpos  stream  operation 

123 
set-pointer  stream  operation    123 
set-reverse-video-p  method 

76 
settable- instance-variables 

deffiavor  option    19 
: string-for-host  method    133 
: string-f or-printing  method 

133 
:  string- in  stream  operation    121 
:  string-out  stream  operation 

120-121 
: trans lated-pathname  method 

135 
:  truename  stream  operation    128 
:tyi 

method   76 

stream  operation    120,  126 
:  ty i -no-hang  stream  operation    1 22 
:  tyipeek  stream  operation    121 
:tyo  stream  operation    120,  124,  126 
:  type  method    133 
:typeout-execute  blip   88-89 
:  untyi  stream  operation    120,125 
: version 

make-system  option    168 

method    133 
: which-operations 

method   3 1 

stream  operation    120 
: who- line -documentation- 
string  method   89 
-[  format  directive    140 


228 


INDEX 


~  {  format  directive    140 

Abort  key   7,  51 

activation  in  the  input  editor   54 

active  processes   45 

advising  functions   51 

after  daemon   26,  84,  88-89 

allocate-resource  function    162, 

164 
allocation,  resource    161 
always  loop  keyword   70 
and 

loop  keyword   70 

special  form   62 
append  loop  keyword   69 
apropos  function    52 
arrest-reasons  instance  variable 

45 
arresting  processes   45 
background  window    124 
base-flavor-first   29 
base-flavor-last   29 
beep  function   73 
before  daemon   26,  84,  89 
bit-save  array  47 
blinker 

: character    186 

mouse    184-186 
blip 

:menu    141-143 

: typeout-execute    88-89 
block  special  form   63 
boot 

cold    11 

warm    1 1 
Boot  Fep  command    1 1 
bp   202 

bridge   214,  216 
brightness,  display    12 
buffer 


i/o   85,  89 

pointer   202 

shared  i/o    141 
bugs,  reporting   52 
c-A  Zmacs  command   222 
c-Abort   7 
c-B 

debugger  command   51 

Zmacs  command   222 
c-D  Zmacs  command   222 
c-E 

debugger  command    52 

Zmacs  command   222 
c-Escape  input  editor  command   53 
c-F  Zmacs  command   222 
c-Help  input  editor  command   53 
c-K 

input  editor  command   53 

Zmacs  command   222 
c-M  debugger  command   52 
c-m-[  Zmacs  command   222 
c-m-]  Zmacs  command   222 
c-m-A 

debugger  command    5 1 

Zmacs  command   222 
c-m-Abort   7 

c-m-B  Zmacs  command  222 
c-m-E  Zmacs  command  222 
c-m-F  Zmacs  command  222 
c-m-K  Zmacs  command  222 
c-m-L 

debugger  command    51 

Zmacs  command   223 
c-m-R  debugger  command   52 
c-m-Rubout  Zmacs  command   222 
c-m-Suspend   7 
c-m-Y 

input  editor  command   53 

Zmacs  command   54 


INDEX 


229 


C-N 

debugger  command   5 1 

Zmacs  command   222 
c-P 

debugger  command   5 1 

Zmacs  command   222 
c-R  debugger  command   52 
c-sh-A 

input  editor  command   54 

Zmacs  command    54 
c-sh-C  Zmacs  command   223 
c-sh-E  Zmacs  command   223 
c-sh-M  Zmacs  command   71,  77 
c-Space  Zmacs  command    223 
c-Suspend    7 
c-W 

input  editor  command   53 

Zmacs  command   223 
c-X 

(  Zmacs  command    199 

)  Zmacs  command    199 

B  Zmacs  command   223 

c-B  Zmacs  command   223 

c-F  Zmacs  command    13,  223 

c-S  Zmacs  command    13,  223 

c-W  Zmacs  command   223 

D  Zmacs  command    13,  224 

E  Zmacs  command    199 
c-Y 

input  editor  command   53 

Zmacs  command   53,  222 
canonical  type    130 
case  in  pathnames    131 
catch  special  form   64,  76 
catch-error  macro    176 
chaos  :  open- stream  function    217 
Chaosnet   211,  213-215 

addresses   215 
check-arg  macro    176 


check-arg-type  macro    176 
chosen-item  instance  variable    142 
circular-list  function   76 
Clear   Input 

input  editor  command   53 

Zmacs  command   222 
clear-resource  function    165 
clock  function  list   44 
cold  boot    1 1 
cold-load  stream   45,  50 
collect  loop  keyword   69,  76 
combined  methods   23 
command 

Edit  Namespace  Object  9 

extended    184,  188 

Halt  Machine    11 

history   54 

Login  9 

menu    141,  143,  183 

Reset   Network   215 

Show  Documentation   8 
Command  Processor   8 
Common  Lisp  6 
Compile 

Buffer,  M-x   223 

File,  M-x   223 
component  flavors   22,  155 
comtab    183-184,  188 
cond  special  form   61 
cond-every  macro   63 
condition    173 

simple    175 
condition  flavor    175 
condition-bind  macro    177,180 
condition-bind-def ault  macro 

178 
condition-case  macro    174,  176 
condition-case  clause,    : no-error 

177 


230 


INDEX 


conditional   61 
conditions 

proceeding    174-175,  177,  179 

signaling  and  handling    173 
Continue  Fep  command    10 
continue -whopper  function   27 
control,  flow  of  61 
Converse   6,  201 
Copy  File,  M-x    127 
copyf  function    127 
count  loop  keyword   69 
current  process   43 

resetting  the   46 
daemon 

after   26,  84,  88-89 

before   26,  84,  89 
dbg  function   51,  59 
dbg :  arg  function    51 
dbg:  loc  function   51 
deactivated  windows  46-47 
deallocate-resource  function 

162,  164 
deal locate -whole -re source 

function    165 
deallocation,  resource    161 
debugger   5 1 

command,   c-B   51 

command,   c-E   52 

command,   c-M  52 

command,   c-m-A  51 

command,   c-m-L   51 

command,   c-m-R  52 

command,   c-N   51 

command,   c-P   51 

command,   c-R  52 
debugging   50 
deexposed  windows   46 
deexposed-typeout-action 

instance  variable   47 


default 

handler    178 

handler  for  streams    120,  122,  124 

pathnames    132 
def  const  special  form   36 
defflavor  option 

:default-init-plist   87-88 

: gettable-instance- 
variables    19 

: included-f lavors   23 

: initable-instance- 
variables   20 

: method-combination   28 

:required-init-keywords    84 

: settable-instance- 
variables    19 
defflavor  special  form    18 
def  method  special  form    18 
defresource  option 

: checker    163 

: constructor    162 

: finder    163 

:free-list-size    164 

: initial-copies    163 

: initializer    162 

: matcher    163 
defresource  macro    162 
def  select  macro   76 
defstruct 

zweirbp  202 

zwei:line   202 

zwei: window  202 
defsystem 

clause,    :compile-load    166 

clause,    ."component- systems 
167 

clause,    :  do- components    167 

clause,    :fasload   166 

clause,    :  module    166 


INDEX 


231 


clause,    :  package    167 

clause,    rpatchable    167 

clause,    :  pathname-default 
166 

dependency    1 66 

transformation    167 
def  system  macro    165 
def  un-method  macro   84 
defvar 

macro   84 

special  form   36 
def  whopper  macro   27 
def window-resource  macro    170 
deletef  function    127 
dependency,  defsystem    166 
describe  function   21 
Describe  Key  Bindings,  M-x    184 
device  pathname  component    131 
Dictionary,  Hacker's    11,  31,  34,  54, 

58,  71,91,  135,  143,  167,  178 
directory    128 
directory  pathname  component 

131 
Dired    13 

disassemble  function   52 
dispatch  macro   63 
display  brightness    12 
Display  Font,  M-x    185 
do 

loop  keyword   68,  70 

special  form   63-64,  66 
Document  Examiner  6 
dolist  macro   67,  76 
dotimes  macro   67 
edit  screen  menu   36,  49,  90 
Edit  Namespace  Object  com- 
mand  9 
Edit 

Callers,  M-x   52 


Combined  Methods,  M-x   52 

Extended  Command,  M-x    184 

Key,  M-x    184 

Methods,  M-x   52 
editor,  Zmacs   6,  12,  53-54,  199,  221 
else  loop  keyword   70 
End 

input  editor  command   54 

Zmacs  command   224 
End  key   71 
error 

flavor    175,  179 

function    175 
error-output  variable    124 
error-restart  macro    179 
error-restart-loop  macro    179 
errset  macro    176 
Escape  input  editor  command   53 
essential-mouse's  method  for 

:mouse-click  30 
ethernet   213-214 
Evaluate 

Buffer,  M-x   223 

Into  Buffer,  M-x   206 
example 

graph   83 

moving  icons    183 

tree    139 
exposed  windows  47 
extended  command    184,  188 
FEP    10 
Fep  command 

Boot    11 

Continue    10 

Set  Chaos-address   216 

Start    11 
f  error  function    176 
fibonacci  numbers   74 
file    125 


232 


INDEX 


File  System  Maintenance   6 
finally  loop  keyword   70,  77 
finger   7 

flashy  scrolling    155 
flavex:  flavor  flavor  40 
flavor    1 7 

condition   175 

error    175,  179 

f 1 a vex : f 1 a vor   40 

fs:pathname    129 

f s :unix-pathname    129 

net: basic-host    130,  133 

si : vanilla-flavor   30,84 

sys: abort    179 

tv: basic-mouse- sensitive- 
items  88-90,  195 

tv : bordered-constraint- 
frame  141 

tv : bordered-constraint- 
f rame -with- shared- io- 
buffer  141 

tv:dont-select-with- 
mouse-mixin  87 

tv:f lashy-scrolling-mixin 
155 

tv: lisp-listener  17,85 

tv: lisp-listener-pane  87 

tv:pane-mixin  87 

tv:pane-no-mouse-select- 
mixin  87,  185 

tv:process-mixin  88,  184 

tv:  sheet  47,  88 

tv: stream-mixin  44 

zwei: buffer  202 

zwei : file-buff er  202 

zwei : interval  202 

zwei: interval-stream  202 

zwei: node  202 

zwei: top-level-node   202 


zwei :window-with-comtab 
184-185 
Flavor  Examiner   6,  33,  59 
flavors 

component   22,  155 

mixing   22 
flow  of  control   61 
font-map  instance  variable   88 
Font  Editor    185 
for  loop  keyword   68,  70 
format  directive 

-[    140 

-{    140 
format  function    140 
frame   85 

Front-End  Processor    10 
f s : change-file-properties 

function    1 27 
f  s  :  complete -pathname  function 

128 
f s:def ine-canonical-type  func- 
tion   132 
fs:directory-list  function    128 
fs  :  file-properties  function    127 
f s : make- logical-pathname- 
host  function    134,171 
f  s  :  make-pathname  function    1 32 
fs:merge- pathnames  function    132 
fs:parse -pathname  function    129 
f  s  :  pathname  flavor    1 29 
f s : set-logical-pathname-host 

function    1 34 
f  s  :  unix-pathname  flavor    1 29 
function 

♦throw  64 

allocate-resource  162,  164 

apropos  52 

beep  73 

chaos : open- stream  217 


INDEX 


233 


circular-list   76 

clear-resource    165 

continue -whopper   27 

copyf  127 

dbg  51,  59 

dbg:arg  51 

dbg:loc  51 

deallocate-resource  162, 
164 

deal locate -whole -re source 
165 

deletef  127 

describe  21 

disassemble  52 

error  175 

ferror  176 

format  140 

f s : change-file-properties 
127 

f s: complete-pathname  128 

f s : def ine-canonical-type 
132 

f s:directory-list  128 

f s :f ile-properties  127 

f s : make-logical-pa thname- 
host  134,  171 

f s :make -pathname  132 

f s :merge-pathnames  132 

f s : parse-pathname  129 

f s : set-logical-pathname- 
host  134 

gensym  85 

grind-top-level  71 

hostat  219 

intern  76 

load  127 

load-patches  168 

login  9 

macroexpand  71 


make-instance  19,  84 

make-system  165,  167-168 

map-resource  165 

mapcan  66,  76 

mapcar  66,  69 

mapcon  66,  76 

maplist  66 

mexp  71,  74 

nconc  66 

net : f ind-paths-to-service 
218 

net : invoke-service- 
access-path  218 

net : invoke-service-on- 
host  218 

netirenable  215,  219 

neti:reset  215,  219 

open  125,  201 

probef  127 

process-run-function  46, 
143 

process-wait  44,  47 

read  205 

readline  204 

renamef  127 

rplacd  76 

send  19 

si : examiner-compute- 
magic-list  40 

si:halt  11 

si:login-to-sys-host  9 

si rmake-serial-stream  217 

si:parse-host  218 

si : set-system-source-file 
168 

signal  175,  180 

spec  51 

stream-default-handler  124 

string-append  76 


234 


INDEX 


tv : add- to- system-menu - 
programs -column  188 

tv:get-line-from-keyboard 
90 

tv: make -window  19,  48 

tv: menu- choose  143 

tv: mouse-set-blinker  186 

tv : mouse-set-blinker- 
definition  186 

tv: select-or-create- 
window-of -flavor  189 

viewf  127 

who-calls  52 

zwei: command-store  201 

zwei : completing-read- 
from-mini-buf f er  205 

zwei : find-combined- 
methods  40 

zwei: interval-stream  202 

zwei : interval-stream- 
into-bp  206 

zwei :make-command-alist 
188 

zwei : open-editor-stream 
201 

zwei: read-buffer-name  205 

zwei : read-def aulted- 
pathname  205 

zwei : set-comtab  188,201 

zwei : set-comtab- 
indirection  188 

zwei : type in- line - 

completing-read  205 

zwei : typein-line-f orm-to- 
eval  205 

zwei :typein-line-multi- 
line-read  205 

zwei:typein-line-read  204 

zwei :typein-line-readline 
204 


Function 

Apropos,  M-x   52 

key   6,  45,  47-50;  59,  219 
gensym  function   85 
go  special  form   68 
graph  example  83 
grind-top-level  function   71 
grindef  special  form   52 
Hacker's  Dictionary    11,  31,  34,  54, 

58,  71,  91,  135,  143,  167,  178 
Halt  Machine  command    11 
handler    173-174 

default    178 

restart    174,  178 
Help  Zmacs  command    13,  221,  224 
Help  key   6,  184 
history 

command   54 

input   53 

kill   53 
host 

logical    133 

physical    134 

table   216 
host  pathname  component    130 
hostat   7,  219 
hostat  function   219 
hyper-control- Function    1 1 
i/o  buffer   85,  89 

shared    1 4 1 
if  macro  62 
ignore  variable   84 
ignore-errors  macro    176 
inactive  processes  45 
inferiors  instance  variable  46 
init  keyword 

:blinker-p  88 

: configurations  87 

: default-font  185 


INDEX 


235 


: item-list    185 
: panes   87 
rprocess   88 
:rows    185 
: selected-pane   87 
initial  values  for  instance  variables   20 
initially  loop  keyword   70 
input 

editor   53 

editor,  activation  in  the   54 
editor  command,   c-Escape   53 
editor  command,   c-Help   53 
editor  command,   c-K  53 
editor  command,   c-m-Y  53 
editor  command,   c-sh-A  54 
editor  command,   c-W  53 
editor  command,   c-Y  53 
editor  command,   Clear   Input 

53 
editor  command,   End   54 
editor  command,   Escape   53 
editor  command,  m-D  53 
editor  command,  m-Rubout   53 
editor  command,  m-Y  53 
history   53 
Inspector   6 

Install  Macro,  M-x   200 
instance    17 

variable,   arrest-reasons   45 
variable,   chosen- item   142 
variable,   deexposed-typeout- 

action  47 
variable,   font-map  88 
variable,   inferiors   46 
variable,   item-list    142 
variable,    item-type-alist 

88-89 
variable,   run-reasons   45 
variable,   superior  46 


variable,   tv:  current-font    186 

variable,   tv:  item-list    195 

variable,  x-offset    187 

variable,  y-offset    187 

variables    1 7 

variables,  initial  values  for   20 
intern  function   76 
Internet   211,  213-214,  216 
interval   202 
ip-tcp   213 
item,  menu    142,  185 
item-list  instance  variable    142 
item-type-alist  instance  variable 

88-89 
iteration   64 
key 

Abort   7,  51 

End   71 

Function   6,  45,  47-50,  59,  219 

Help  6,  184 

Local    12 

Resume   7,  51 

Select   6,  48-49,  87 

Suspend   7,  184 
keyboard   5 

macro    1 99 
keys,  modifier   5 
kill  history   53 
kwc-letf  macro   39 
let  special  form   69 
let-globally  special  form   32 
letf  special  form   39 
line  202 

lisp  listener   8,  53 
List 

Callers,  M-x   52 

Combined  Methods,  M-x   37,  40, 
52 

Fonts,  M-x    185 


236 


INDEX 


Methods,  M-x    52 

Variables,  M-x    184 
load  function    127 
load-patches  function    168 
Local  key    1 2 
locks,  window   50 
logical 

host    133 

pathname    133 
login  function   9 
Login  command   9 
Lookup  Key  Bindings,  M-x    184 
loop  keyword 

always   70 

and   70 

append  69 

collect  69,  76 

count   69 

do  68,  70 

else   70 

finally   70,  77 

for   68,  70 

initially  70 

maximize   69 

minimize   69 

nconc   69 

never   70 

repeat   68,  76 

return   70 

sum   69 

thereis   70,  77 

unless   70 

until   70 

when   70,  76 

while   70 

with   69 
loop  macro   64,  68 
m- .  Zmacs  command    13,  71,  224 
m-<  Zmacs  command   222 


m->  Zmacs  command   222 

m-  [  Zmacs  command   222 

m-  ]  Zmacs  command   222 

m-A  Zmacs  command   222 

m-Abort   7 

m-B  Zmacs  command   222 

m-D 

input  editor  command   53 

Zmacs  command   222 
m-E  Zmacs  command   222 
m-F  Zmacs  command   222 
m-K  Zmacs  command   222 
m-Rubout 

input  editor  command   53 

Zmacs  command   222 
m-sh-M  Zmacs  command   71,  77 
m-Suspend   7,  51 
m-W  Zmacs  command   223 
M-x 

Compile  Buffer   223 

Compile  File   223 

Copy  File    127 

Describe  Key  Bindings    184 

Display  Font    185 

Edit  Callers   52 

Edit  Combined  Methods   52 

Edit  Extended  Command    184 

Edit  Key    184 

Edit  Methods   52 

Evaluate  Buffer   223 

Evaluate  Into  Buffer   206 

Function  Apropos   52 

Install  Macro   200 

List  Callers   52 

List  Combined  Methods   37,  40,  52 

List  Fonts    185 

List  Methods   52 

List  Variables    184 

Lookup  Key  Bindings    184 


INDEX 


237 


Name  Last  Kbd  Macro   200 

Set  Variable    184 

Trace   50 
m-Y 

input  editor  command   53 

Zmacs  command   53-54,  222 
macro   62,  71 

catch-error    176 

check-arg    176 

check-arg-type    176 

cond-every   63 

condition-bind    177,  180 

condition-bind-default    178 

condition-case    174,  176 

defresource    162 

defselect  76 

defsystem   165 

defun-method   84 

defvar    84 

defwhopper  27 

def window-resource  170 

dispatch  63 

dolist  67,  76 

dotimes  67 

error-restart  179 

error-restart-loop  179 

errset  176 

if  62 

ignore-errors  176 

keyboard  199 

kwc-letf  39 

loop  64,  68 

net : invoke-multiple- 
services  218 

select  62 

selector  62 

selectq  62,  76 

selectq-every  63 

setf  51 


signal-proceed-case  180 

tv: add- typeout- item-type 
89,  195 

typecase  63 

unless  62 

using-resource  162,  164 

when  62 

with-open-f ile  126,  201 

zwei: def com  188,  201 

zwei : def ine-keyboard- 
macro  200 

zwei: mark  203 

zwei: point   203 

zwei :with-editor-stream 
201 
macroexpand  function   71 
make-instance  function    19,  84 
make -system  function    165,167-168 
make-system  option 

: compile    167 

:noconfirm   168 

: print-only   168 

:version    168 
map-resource  function    165 
mapcan  function   66,  76 
mapcar  function   66,  69 
mapcon  function   66,  76 
maplist  function   66 
mapping  operators   64-65 
margins,  window   76 
maximize  loop  keyword   69 
medium   211-212 
menu    142 

command    141,  143,  183 

edit  screen   36,  49,  90 

item    142,  185 

system    12,  36,  45-46,  48,  50,  188 

trace   50 
merging  pathnames    132 


238 


INDEX 


method  1 7 

: activate  48 

: alias -for- selected- 
windows  87 

:bury  49 

.•canonical -type    133 

:  choose    142-143 

: clear-window  76,  195 

: compute-all-handlers- 
once   40 

: deactivate   48 

rdeexpose   48-49 

rdescribe   31 

rdeselect   48 

.•device    133 

: directory  133 

: draw-char  195 

: draw-circle  76 

: draw-line  36 

: draw-lines  36 

: draw-point  76 

: draw-rectangle  76 

: draw-triangle  76 

:  execute    141-143 

: expose   48 

: force-redisplay  202 

:get    133 

:get-handler-for  31 

:host  133 

:init  84 

: inside-size  76 

:item  90,  195 

:kill  48 

: mouse -buttons  142 

:  mouse-click  29,86,89-90, 
143 

: mouse -moves  90 

: mouse-standard-blinker 
186-187 


name  133 

new-canonical-type  133 
new-device  133 
new-directory  133 
new-name  133 
new-pathname  133 
new-raw-device  133 
new-raw-directory  133 
new-raw-name  133 
new-raw-type  133 
new- type  133 
new-version  133 
plist  133 

primitive-item  90,  195 
print-self  31,  140 
proceed  178,  180 
proceed-type-p  180 
proceed-types  180 
properties  133 
putprop  133 
raw-device  133 
raw-directory  133 
raw-name  133 
raw-type  133 
remprop  133 
report  175 
reverse-video-p  76 
select  48,  87 
selectable-windows  87 
send-if -handles  84 
set-character  186 
set-reverse-video-p  76 
string-for-host  133 
string-for-printing  133 
trans lated-pathname  135 
tyi  76 
type  133 
version  133 
which-operations  31 


INDEX 


239 


:who-line-documentation- 

string   89 
combination,    :case    180 
combination,    :or   29,  89 
combination,    :  override   89 
for    :  mouse -click,  essential- 
mouse's   30 

methods 

combined   23 
primary   25 

mexp  function   71,  74 

mini-buffer, 

pop-up    183-184 
reading  from  the   204 

minimize  loop  keyword   69 

mixing  flavors   22 

modifier  keys   5 

more  processing   50 

mouse 

blinker    184-186 
documentation  line   89 
process   29,  46,  58,  86,  88,  143, 
187 

mouse 

drag   left  Zmacs  command   223 
left  Zmacs  command   222 
middle  Zmacs  command   223 

mouse-sensitive  items   85,  88-89 

moving  icons  example    183 

multiple  windows  and  processes   85 

Murray  Hill  standard  utilities   52,  59 

name  pathname  component    1 3 1 

Name  Last  Kbd  Macro,  M-x   200 

namespace   9,211,214,216-217 

nconc 

function   66 
loop  keyword   69 

net: basic-host  flavor    130,133 

net : f ind-paths-to-service 
function   218 


net : invoke-multiple-services 

macro   218 
net : invoke-service-access- 

path  function   218 
net : invoke-service-on-host 

function   218 
neti tenable  function   215,219 
neti:  reset  function   215,  219 
network  211 
never  loop  keyword   70 
nonlocal  exits  64 
Notifications  window   6 
open  option 

:byte-size    126 

: direction   125 

:if-exists    126 
open  function    125,  201 
or  special  form   62 
output  hold   47 
package    1 2 

user    12 
pane   85 
pathname    129 

component,   device    131 

component,   directory   131 

component,  host   130 

component,  name    131 

component,  type    130 

component,  version   130 

components    1 30 

logical    133 

physical    134 
pathnames 

case  in    131 

default    132 

merging    132 
Peek  6,  45-47,  49,  219 
physical 

host    134 


240 


INDEX 


pathname    134 
point   202 

pop-up  mini-buffer    183-184 
primary  methods   25 
prime  numbers   74 
probef  function    127 
proceed  types    180 
proceeding  conditions    174-175,  177, 

179 
process   43,  85 

current   43 

mouse   29,  46,  58,  86,  88,  143,  187 
process-run-function  function 

46,  143 
process-wait  function   44,  47 
processes 

active  45 

arresting   45 

inactive   45 

multiple  windows  and   85 

resetting   45 

un-arresting  45 
processing,  more   50 
prog  special  form   63,  68 
protocol   211-212 
race  condition   86 
read  function   205 
reading  from  the  mini-buffer   204 
readline  function   204 
renamef  function    127 
repeat  loop  keyword   68,  76 
reporting  bugs   52 
Reset  Network  command   215 
resetting 

processes   45 

the  current  process   46 
resource    1 6 1 

allocation    161 

deallocation    161 


restart  handler    174,  178 
Resume  key   7,  51 
return 

loop  keyword   70 

special  form   64,  77 
return- from  special  form   63 
rplacd  function   76 
Rubout  Zmacs  command   222 
run  bars    12 

run-reasons  instance  variable   45 
s-E  Zmacs  command   224 
scheduler  43 
screen   46 

scrolling,  flashy    155 
select  macro   62 
Select  key  6,  48-49,  87 
selected  windows   47 
selector  macro  62 
selectq  macro   62,  76 
selectq-every  macro   63 
self  variable    19 
send  function    19 
serial 

lines   214,217 

streams   217 
serial-pseudonet   214 
service   211-212,  218 

access  path   218 

futures   218 
Set  Chaos-address  Fep  command 

216 
Set  Variable,  M-x    184 
setf  macro   51 
shared  i/o  buffer    141 
Show  Documentation  command   8 
si : examiner-compute-magic- 
list  function   40 
si  :halt  function    11 
si  :  login-to-sys-host  function   9 


INDEX 


241 


si  :make-serial-stream  function 

217 
si: parse-host  function   218 
si : set-system-source-file 

function    168 
si  :  vanilla-flavor  flavor   30,  84 
signal  function    175,  180 
signal-proceed-case  macro    180 
signaling  and  handling  conditions    173 
simple  condition    175 
site  directory    134,  168,  170 
spec,  function   51 
special  form 

♦catch  64 

and  62 

block  63 

catch  64,  76 

cond  61 

defconst   36 

def flavor    18 

def method    18 

defvar   36 

do   63-64,  66 

go  68 

grindef   52 

let   69 

let-globally  32 

letf   39 

or   62 

prog  63,  68 

return   64,  77 

return-from  63 

throw  64,  76 

trace   50 

untrace   50 
standard  utilities,  Murray  Hill   52,  59 
standard- input  variable    123 
standard-output  variable    123 
Start  Fep  command    1 1 


stream    119 
cold-load   50 

operation,    :  characters    121 
operation,    :  clear-input    122 
operation,    :  clear-output    122 
operation,    :  clear-screen   123 
operation,    :  clear- window   123 
operation,    :  close    122 
operation,    :  creation-date    128 
operation,    :  direction    121 
operation,    :  finish   122 
operation,    :  force-output    122 
operation,    :  length   128 
operation,    :  listen    121 
operation,    :  pathname    128 
operation,    :read-cursorpos 

122 
operation,    :  read-pointer    123 
operation,    :  set-cursorpos    123 
operation,    :  set-pointer    123 
operation,    :  string-in   121 
operation,    :  string-out    120-121 
operation,    :  truename    128 
operation,    :tyi    120,  126 
operation,    :tyi -no-hang    122 
operation,    :tyipeek   121 
operation,    :tyo    120,  124,  126 
operation,    :untyi    120,  125 
operation,    :which-operations 

120 
synonym    1 24 

stream-default-handler  func- 
tion   124 

streams,  default  handler  for    120,  122, 
124 

string-append  function   76 

subnet   214-216 

sum  loop  keyword   69 

superior  instance  variable  46 


242 


INDEX 


Suspend  Zmacs  command    13,  224 

Suspend  key   7,  184 

synonym  stream    124 

sys  :  abort  flavor    179 

system    165 

menu    12,  36,  45-46,  48,  50,  188 

terminal-io  variable    123 

Terminal  window   6 

terminator   215 

thereis  loop  keyword   70,  77 

throw  special  form  64,  76 

trace  menu   50 

trace  special  form   50 

Trace,  M-x   50 

tracing  functions   50 

transceiver   214 

transferring  text  between  windows   53 

transformation,  defsystem    167 

tree  example    139 

tv : add- to- system-menu- 
programs-column  function    188 

tv:add-typeout- item- type 
macro   89,  195 

tv: basic-mouse- sensitive- 
items  flavor   88-90,  195 

tv : bordered-constraint-f rame 
flavor    1 4 1 

tv : bordered-constraint- 
frame-with- shared- io- 
buf  f  er  flavor    141 

tv: current-font  instance  variable 
186 

tv:dont-select-with-mouse- 
mixin  flavor   87 

tv:f lashy-scrolling-mixin 
flavor    155 

tv:get-line-from-keyboard 
function   90 

tv:  item- list  instance  variable    195 


tv:  lisp-listener  flavor    17,  85 
tv:  lisp-listener-pane  flavor   87 
tv: main- screen  variable    187 
tv:  make -window  function    19,  48 
tv: menu-choose  function    143 
tv: mouse-process  variable   46 
tv: mouse-set-blinker  function 

186 
tv: mouse -set-blinker- 
definition  function    186 
tv :  pane -mixin  flavor   87 
tv:pane-no-mouse-select- 

mixin  flavor   87,  185 
tv : previously-selected- 
windows  variable   47,  49 
tv:  process -mixin  flavor   88,184 
tv: select-or-create-window- 

of- flavor  function    189 
tv:  selected-window  variable   48 
tv:  sheet  flavor   47,  88 
tv :  stream-mixin  flavor   44 
type  pathname  component    1 30 
typecase  macro   63 
typein  line   204 
typeout  window    13,184 
un-arresting  processes   45 
unless 

loop  keyword   70 
macro  62 
until  loop  keyword   70 
untrace  special  form   50 
user  package    12 

using-resource  macro    162,  164 
variable 
*   52-53 

error-output    124 
ignore   84 
self    19 
standard- input    123 


INDEX 


243 


standard-output    123 

command, 

c-A  222 

terminal-io   123 

command, 

c-B  222 

tvrmain-screen    187 

command, 

c-D   222 

tv: mouse-process   46 

command, 

c-E   222 

tv: previously- selected- 

command, 

c-F   222 

windows    47,  49 

command, 

c-K  222 

tv : selected-window 

48 

command, 

c-m-[    222 

zwei:*interval*   202 

204 

command, 

c-m-]    222 

zwei : *numeric-arg* 

188 

command, 

c-m-A  222 

zwei: * standard- comtab*   201 

command, 

c-m-B  222 

zwei : *window*   202,204 

command, 

c-m-E  222 

zwei : *zmacs-comtab* 

201 

command, 

c-m-F   222 

version  pathname  component    130 

command, 

c-m-K  222 

viewf  function    127 

command, 

c-m-L   223 

wait-function   44 

command, 

c-m-Rubout   222 

warm  boot    1 1 

command, 

c-m-Y   54 

when 

command, 

c-N  222 

loop  keyword   70,  76 

command, 

c-P   222 

macro   62 

command, 

c-sh-A   54 

while  loop  keyword   70 

command, 

c-sh-C   223 

who- calls  function   52 

command, 

c-sh-E   223 

whopper   26 

command, 

c-sh-M  71,  77 

window   46,  85 

command, 

c-Space   223 

background    124 

command, 

c-W  223 

locks    50 

command, 

c-X    (    199 

margins   76 

command, 

c-X    )    199 

windows 

command, 

c-X  B   223 

and  processes,  multiple   8f 

command, 

c-X  c-B  223 

deactivated   46-47 

command, 

c-X  c-F    13,  223 

deexposed   46 

command, 

c-X  c-S    13,  223 

exposed   47 

command, 

c-X  c-W  223 

selected   47 

command, 

c-X  D    13,  224 

transferring  text  between 

53 

command, 

c-X  E    199 

with  loop  keyword   69 

command, 

c-Y   53,  222 

with-open-f  ile  macro    126,  201 

command, 

Clear   Input   222 

wrapper   28 

command, 

End   224 

x-of  f  set  instance  variable 

187 

command, 

Help    13,  221,  224 

y-of  f  set  instance  variable 

187 

command, 

m-.    13,71,224 

Zmacs 

command, 

m-<   222 

244 


INDEX 


command,  m->   222 

command,  ra-[    222 

command,  m-]    222 

command,  m-A  222 

command,  m-B  222 

command,  m-D   222 

command,  m-E   222 

command,  m-F  222 

command,  m-K  222 

command,  m-Rubout   222 

command,  m-sh-M  71,  77 

command,  m-W  223 

command,  m-Y   53-54,  222 

command,  mouse  drag   left 
223 

command,  mouse   left   222 

command,  mouse  middle   223 

command,   Rubout   222 

command,   s-E   224 

command,   Suspend    13,  224 

editor   6,  12,  53-54,  199,  221 
Zmail   6,  201 
zwei :  *interval*  variable   202, 

204 
zwei :  *numeric-arg*  variable    188 
zwei :  *standard-comtab*  variable 

201 
zwei  :  *window*  variable   202,  204 
zwei :  *zmacs-comtab*  variable 

201 
zwei  :  bp  defstruct   202 
zwei  :  buff  er  flavor   202 
zwei  :  command- store  function   201 
zwei : completing-read-f rom- 

mini-buf  f  er  function  205 
zwei  :def  com  macro  188,201 
zwei : def ine-keyboard-macro 

macro   200 
zwei  :  file-buffer  flavor   202 


zwei : find-combined-methods 

function   40 
zwei:  interval  flavor   202 
zwei : interval-stream 

flavor   202 

function   202 
zwei : interval-stream-into-bp 

function   206 
zwei  :  line  defstruct   202 
zwei :make-command-alist  func- 
tion   188 
zwei  :mark  macro   203 
zwei  mode  flavor   202 
zwei : open-editor-stream  func- 
tion   201 
zwei  :  point  macro   203 
zwei  :  read-buff  er-name  function 

205 
zwei : read-def aulted-pathname 

function   205 
zwei  :  set-comtab  function    188, 

201 
zwei : set-comtab-indirection 

function    188 
zwei: top-level-node  flavor   202 
zwei : type in- line - 

completing-read  function   205 
zwei : typein-line-f orm-to- 

eval  function   205 
zwei : typein-line-multi- 

line-read  function   205 
zwei :  typein-line-read  function 

204 
zwei : typein-line-readline 

function   204 
zwei  :  window  defstruct   202 
zwei :window-with-comtab  flavor 

184-185 
zwei :with-editor-stream  macro 

201 


Please  send  me  a  copy  of  the  examples  tape  that  accompanies  Using  the 
Lisp  Machine.  Enclosed  is  my  check  for  $40.00,  plus  applicable  sales  tax,* 
made  payable  to  Symbolics,  Inc.  This  fee  includes  domestic  postage  and 
handling.  (Outside  North  America,  add  $10.00  for  postage.) 

Ship  the  tape  to  the  following  street  address  (no  PO  boxes,  please): 


(name) 


(company) 


(street) 


(city)  (state)  (zip) 


(         ) 
(phone) 


♦Residents  of  the  following  states  add  appropriate  sales  tax:  AZ,  CA,  CO.  CT,  FL,  GA,  IL.  K.S.  MA, 
MN,  NJ,  NM,  NY,  OH,  PA,  TX,  VA,  WA. 


LISP  LORE:  A  GUIDE  TO  PROGRAMMING  THE 
LISP  MACHINE  is  a  course  in  programming  a  Lisp 
machine.  The  book  presents  a  readily  understandable 
introduction  to  several  representative  areas  of  interest, 
including  enough  information  to  show  how  easy  it  is  to 
build  useful  programs  on  the  Lisp  machine.  A  graduated 
series  of  exercises,  with  hints  and  solutions,  is  also 
included  in  the  text. 

The  book  assumes  some  background  in  LISP  and  experi- 
ence with  some  dialect  of  the  language;  however,  no 
experience  with  the  Lisp  machine  itself  is  required. 


Klu  wer  A  cademic  Publishers  0-89838-220-3